Compare commits
264 Commits
feat/xxhas
...
v1.121.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
98c9ae1f7d | ||
|
|
1d8673eb3b | ||
|
|
026482099a | ||
|
|
c17c174149 | ||
|
|
cfba7f7701 | ||
|
|
ad510dd6fd | ||
|
|
a3712e40bd | ||
|
|
34fae31fd4 | ||
|
|
f8bbc6eabe | ||
|
|
69e50d0d27 | ||
|
|
3a2e30e30e | ||
|
|
53940f7d42 | ||
|
|
b66c53bef3 | ||
|
|
1737013e66 | ||
|
|
bcd17c2ebe | ||
|
|
b031a8cac1 | ||
|
|
41f138d3c8 | ||
|
|
6b5defc27b | ||
|
|
2604940f09 | ||
|
|
32f908baf1 | ||
|
|
944ea7dbcd | ||
|
|
4b5657c21e | ||
|
|
f5c4af73aa | ||
|
|
24ae4ecff1 | ||
|
|
64a7baec8c | ||
|
|
caf6c0996d | ||
|
|
6729782c3f | ||
|
|
a60209db3e | ||
|
|
d1169e3b2f | ||
|
|
df972ef711 | ||
|
|
33263cf9f3 | ||
|
|
1b5811d992 | ||
|
|
1fa0122eda | ||
|
|
d1085e8a02 | ||
|
|
d6a70bc7e5 | ||
|
|
d3fe238eef | ||
|
|
35f24270fe | ||
|
|
1f1a4ab1a3 | ||
|
|
0b3742cf13 | ||
|
|
9203a61709 | ||
|
|
11403abfbc | ||
|
|
5a2af558fb | ||
|
|
de993289ad | ||
|
|
c58bd307ce | ||
|
|
333ca8827e | ||
|
|
3dad19883d | ||
|
|
4ca27a3e7f | ||
|
|
b0bb11f9e0 | ||
|
|
ecb8349085 | ||
|
|
e1feba2198 | ||
|
|
53a7ac3868 | ||
|
|
f2e950d89c | ||
|
|
8ba2c99b08 | ||
|
|
93346496fc | ||
|
|
a9525de356 | ||
|
|
31a1e64b58 | ||
|
|
e17bd8efc6 | ||
|
|
2f9019c0e1 | ||
|
|
dfa8a8a6e1 | ||
|
|
b9a0c3c79f | ||
|
|
bda97c4e0e | ||
|
|
e3426c880f | ||
|
|
d4ca7d0075 | ||
|
|
f1c9b763cf | ||
|
|
5097c92494 | ||
|
|
7aacc92699 | ||
|
|
00d6cc86ad | ||
|
|
54d881e5c6 | ||
|
|
edce096680 | ||
|
|
5c31acbcf0 | ||
|
|
6b49104d59 | ||
|
|
97dbe3236b | ||
|
|
586393f178 | ||
|
|
f3e88ea2fa | ||
|
|
c8b46802d6 | ||
|
|
7534098596 | ||
|
|
ec5b7c266b | ||
|
|
e84ad084d5 | ||
|
|
dc2de47204 | ||
|
|
2fe6607aea | ||
|
|
64831e2328 | ||
|
|
6053214e75 | ||
|
|
599b489f81 | ||
|
|
0b98c5e3c4 | ||
|
|
b238b69689 | ||
|
|
decbc741e2 | ||
|
|
564449a555 | ||
|
|
f4741c70f3 | ||
|
|
be2b76be8c | ||
|
|
cff0b95f4c | ||
|
|
1321a393c1 | ||
|
|
a9fc840d65 | ||
|
|
ebf06dc12e | ||
|
|
8d8becd0f7 | ||
|
|
3b5f5ec57a | ||
|
|
b29e4ec39f | ||
|
|
f1b8a9374f | ||
|
|
497b3d995e | ||
|
|
9fd425dd5c | ||
|
|
442d4e5e1c | ||
|
|
7134d26a19 | ||
|
|
42ee7f1290 | ||
|
|
5d7a04367c | ||
|
|
06e0ba29f8 | ||
|
|
b36de7d7d4 | ||
|
|
d456d35510 | ||
|
|
c383e115af | ||
|
|
5edbb93a4d | ||
|
|
1d55b5bfc0 | ||
|
|
60afd7b400 | ||
|
|
3f99ef90ec | ||
|
|
380fc06979 | ||
|
|
d34d92dca3 | ||
|
|
3551407d95 | ||
|
|
6bfc20ef95 | ||
|
|
eadcbd52fb | ||
|
|
fed882a28a | ||
|
|
cdabd08139 | ||
|
|
b95bc32310 | ||
|
|
b9096f3e99 | ||
|
|
5ac236d6fd | ||
|
|
458f2acf42 | ||
|
|
5b2cd704d3 | ||
|
|
0130052de5 | ||
|
|
16027678ee | ||
|
|
343cdcfeed | ||
|
|
a28b92b3cc | ||
|
|
066682f48d | ||
|
|
7d933ec97a | ||
|
|
30d42e571c | ||
|
|
318ab756cb | ||
|
|
9d75c5b999 | ||
|
|
40fbef50cf | ||
|
|
7961435d36 | ||
|
|
92ad03615c | ||
|
|
33409a8cd0 | ||
|
|
244c8cb4d4 | ||
|
|
0d62ff11f1 | ||
|
|
ae2992a6d8 | ||
|
|
952c6be6ea | ||
|
|
0f668fd5c6 | ||
|
|
19eb3ed8b9 | ||
|
|
2efba6326d | ||
|
|
0230dc284b | ||
|
|
a39a1cfffa | ||
|
|
f776e049e9 | ||
|
|
37e437a568 | ||
|
|
2c86da07c6 | ||
|
|
4b9e460db5 | ||
|
|
143ee0bc34 | ||
|
|
68a4cc25dc | ||
|
|
e74ddca6c0 | ||
|
|
02819dc079 | ||
|
|
6a011a4595 | ||
|
|
e029190a5d | ||
|
|
00dd9419a5 | ||
|
|
96e97278d3 | ||
|
|
e1d968d1b3 | ||
|
|
db69361f19 | ||
|
|
490fcc5591 | ||
|
|
921b7cbc8d | ||
|
|
044c3e93f8 | ||
|
|
8449e78c8f | ||
|
|
f8a2bcee79 | ||
|
|
9204cd6a21 | ||
|
|
988d527212 | ||
|
|
a70ed7c7f6 | ||
|
|
88d85eff0a | ||
|
|
d95b474e58 | ||
|
|
43d18ccc36 | ||
|
|
fb995816a1 | ||
|
|
151ba9f1d9 | ||
|
|
bc06863d28 | ||
|
|
5d9b4b4532 | ||
|
|
a1dd587590 | ||
|
|
7e9fb5df5e | ||
|
|
1ec9a60e41 | ||
|
|
a76c39812f | ||
|
|
c124cf9ace | ||
|
|
110546bab2 | ||
|
|
a93fda8e0d | ||
|
|
d455a547cc | ||
|
|
1ef2804d20 | ||
|
|
d40cbe4c5f | ||
|
|
e98acc976e | ||
|
|
62e0658e5a | ||
|
|
0d4a18151d | ||
|
|
45c86e95e8 | ||
|
|
13d2febc33 | ||
|
|
0cb9c0d20d | ||
|
|
c6227b49ff | ||
|
|
84e6e276bf | ||
|
|
e6a666f1d3 | ||
|
|
16f2364e93 | ||
|
|
21d7cf6de6 | ||
|
|
c77345637b | ||
|
|
b7cd770831 | ||
|
|
791c37d2cc | ||
|
|
d137fc3eb6 | ||
|
|
b411e30796 | ||
|
|
56bebd01df | ||
|
|
45517ab7ae | ||
|
|
ee0130a58b | ||
|
|
62e55f3db9 | ||
|
|
8c38d22f42 | ||
|
|
39b571a95c | ||
|
|
c9c0212ca9 | ||
|
|
4a2a7b7735 | ||
|
|
76c0b964eb | ||
|
|
e1e3ae811d | ||
|
|
3fb5adb31c | ||
|
|
b1149881bd | ||
|
|
12628b80bc | ||
|
|
23646f0d55 | ||
|
|
c8f672f494 | ||
|
|
0eabb3ef80 | ||
|
|
6b2f23b5a3 | ||
|
|
57704ba5a7 | ||
|
|
274381deaa | ||
|
|
7011231c4c | ||
|
|
e3fc4d7b0a | ||
|
|
d9949434f6 | ||
|
|
3d971f69dc | ||
|
|
bb694aeeeb | ||
|
|
3f663106e8 | ||
|
|
79acbc1d7b | ||
|
|
01a9cda15d | ||
|
|
8ac40a933a | ||
|
|
51d4899cd1 | ||
|
|
e8015dc7d7 | ||
|
|
782ba48470 | ||
|
|
c266465317 | ||
|
|
426008b714 | ||
|
|
a17d34b186 | ||
|
|
263d2ba161 | ||
|
|
ece4553321 | ||
|
|
5bb7854f4f | ||
|
|
7d3ed6bd55 | ||
|
|
c653c48ed2 | ||
|
|
240de1239e | ||
|
|
edd7dfb5d8 | ||
|
|
4c55597478 | ||
|
|
7e49b0c875 | ||
|
|
e57bd94f04 | ||
|
|
8eb79805ae | ||
|
|
0a3bfd5cc3 | ||
|
|
f2b799cd6f | ||
|
|
6d56927c2c | ||
|
|
8f69d9d0ec | ||
|
|
0985d7f3c4 | ||
|
|
ee50d0b42a | ||
|
|
b8524680f6 | ||
|
|
22a2bfc812 | ||
|
|
7a78c3372c | ||
|
|
452ce73e7f | ||
|
|
346a0847ef | ||
|
|
f59b813ffe | ||
|
|
1193adf0f5 | ||
|
|
e7397f35c9 | ||
|
|
f29fb1655a | ||
|
|
9bdfb41e9c | ||
|
|
5a3e352950 | ||
|
|
e183ff6feb | ||
|
|
20b4d281bb |
2
.devcontainer/Dockerfile
Normal file
@@ -0,0 +1,2 @@
|
||||
ARG BASEIMAGE=mcr.microsoft.com/devcontainers/typescript-node:22@sha256:dc2c3654370fe92a55daeefe9d2d95839d85bdc1f68f7fd4ab86621f49e5818a
|
||||
FROM ${BASEIMAGE}
|
||||
20
.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "Immich devcontainers",
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile",
|
||||
"args": {
|
||||
"BASEIMAGE": "mcr.microsoft.com/devcontainers/typescript-node:22"
|
||||
}
|
||||
},
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
"svelte.svelte-vscode"
|
||||
]
|
||||
}
|
||||
},
|
||||
"forwardPorts": [],
|
||||
"postCreateCommand": "make install-all",
|
||||
"remoteUser": "node"
|
||||
}
|
||||
|
||||
4
.github/release.yml
vendored
@@ -4,6 +4,10 @@ changelog:
|
||||
labels:
|
||||
- changelog:breaking-change
|
||||
|
||||
- title: 🫥 Deprecated Changes
|
||||
labels:
|
||||
- changelog:deprecated
|
||||
|
||||
- title: 🔒 Security
|
||||
labels:
|
||||
- changelog:security
|
||||
|
||||
2
.github/workflows/cli.yml
vendored
@@ -59,7 +59,7 @@ jobs:
|
||||
uses: docker/setup-qemu-action@v3.2.0
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3.7.0
|
||||
uses: docker/setup-buildx-action@v3.7.1
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
|
||||
4
.github/workflows/docker-cleanup.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
steps:
|
||||
- name: Clean temporary images
|
||||
if: "${{ env.TOKEN != '' }}"
|
||||
uses: stumpylog/image-cleaner-action/ephemeral@v0.8.0
|
||||
uses: stumpylog/image-cleaner-action/ephemeral@v0.9.0
|
||||
with:
|
||||
token: "${{ env.TOKEN }}"
|
||||
owner: "immich-app"
|
||||
@@ -64,7 +64,7 @@ jobs:
|
||||
steps:
|
||||
- name: Clean untagged images
|
||||
if: "${{ env.TOKEN != '' }}"
|
||||
uses: stumpylog/image-cleaner-action/untagged@v0.8.0
|
||||
uses: stumpylog/image-cleaner-action/untagged@v0.9.0
|
||||
with:
|
||||
token: "${{ env.TOKEN }}"
|
||||
owner: "immich-app"
|
||||
|
||||
5
.github/workflows/docker.yml
vendored
@@ -33,6 +33,7 @@ jobs:
|
||||
- 'server/**'
|
||||
- 'openapi/**'
|
||||
- 'web/**'
|
||||
- 'i18n/**'
|
||||
machine-learning:
|
||||
- 'machine-learning/**'
|
||||
|
||||
@@ -124,7 +125,7 @@ jobs:
|
||||
uses: docker/setup-qemu-action@v3.2.0
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3.7.0
|
||||
uses: docker/setup-buildx-action@v3.7.1
|
||||
|
||||
- name: Login to Docker Hub
|
||||
# Only push to Docker Hub when making a release
|
||||
@@ -215,7 +216,7 @@ jobs:
|
||||
uses: docker/setup-qemu-action@v3.2.0
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3.7.0
|
||||
uses: docker/setup-buildx-action@v3.7.1
|
||||
|
||||
- name: Login to Docker Hub
|
||||
# Only push to Docker Hub when making a release
|
||||
|
||||
2
.github/workflows/docs-build.yml
vendored
@@ -27,7 +27,7 @@ jobs:
|
||||
- 'docs/**'
|
||||
- name: Check if we should force jobs to run
|
||||
id: should_force
|
||||
run: echo "should_force=${{ github.event_name == 'release' }}" >> "$GITHUB_OUTPUT"
|
||||
run: echo "should_force=${{ github.event_name == 'release' || github.ref_name == 'main' }}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
build:
|
||||
name: Docs Build
|
||||
|
||||
2
.github/workflows/docs-destroy.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
||||
tg_version: "0.58.12"
|
||||
tofu_version: "1.7.1"
|
||||
tg_dir: "deployment/modules/cloudflare/docs"
|
||||
tg_command: "destroy"
|
||||
tg_command: "destroy -refresh=false"
|
||||
|
||||
- name: Comment
|
||||
uses: actions-cool/maintain-one-comment@v3
|
||||
|
||||
52
.github/workflows/fix-format.yml
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
name: Fix formatting
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [labeled]
|
||||
|
||||
jobs:
|
||||
fix-formatting:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.label.name == 'fix:formatting' }}
|
||||
permissions:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Generate a token
|
||||
id: generate-token
|
||||
uses: actions/create-github-app-token@v1
|
||||
with:
|
||||
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
|
||||
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
|
||||
|
||||
- name: 'Checkout'
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.ref }}
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: './server/.nvmrc'
|
||||
|
||||
- name: Fix formatting
|
||||
run: make install-all && make format-all
|
||||
|
||||
- name: Commit and push
|
||||
uses: EndBug/add-and-commit@v9
|
||||
with:
|
||||
default_author: github_actions
|
||||
message: 'chore: fix formatting'
|
||||
|
||||
- name: Remove label
|
||||
uses: actions/github-script@v7
|
||||
if: always()
|
||||
with:
|
||||
script: |
|
||||
github.rest.issues.removeLabel({
|
||||
issue_number: context.payload.pull_request.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
name: 'fix:formatting'
|
||||
})
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: PR Conventional Commit Validation
|
||||
uses: ytanikin/PRConventionalCommits@1.2.0
|
||||
uses: ytanikin/PRConventionalCommits@1.3.0
|
||||
with:
|
||||
task_types: '["feat","fix","docs","test","ci","refactor","perf","chore","revert"]'
|
||||
add_label: 'false'
|
||||
|
||||
1
.github/workflows/test.yml
vendored
@@ -30,6 +30,7 @@ jobs:
|
||||
filters: |
|
||||
web:
|
||||
- 'web/**'
|
||||
- 'i18n/**'
|
||||
- 'open-api/typescript-sdk/**'
|
||||
server:
|
||||
- 'server/**'
|
||||
|
||||
2
.vscode/settings.json
vendored
@@ -41,4 +41,4 @@
|
||||
"explorer.fileNesting.patterns": {
|
||||
"*.ts": "${capture}.spec.ts,${capture}.mock.ts"
|
||||
}
|
||||
}
|
||||
}
|
||||
18
Makefile
@@ -39,7 +39,7 @@ attach-server:
|
||||
renovate:
|
||||
LOG_LEVEL=debug npx renovate --platform=local --repository-cache=reset
|
||||
|
||||
MODULES = e2e server web cli sdk
|
||||
MODULES = e2e server web cli sdk docs
|
||||
|
||||
audit-%:
|
||||
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) audit fix
|
||||
@@ -48,11 +48,9 @@ install-%:
|
||||
build-cli: build-sdk
|
||||
build-web: build-sdk
|
||||
build-%: install-%
|
||||
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) run | grep 'build' >/dev/null \
|
||||
&& npm --prefix $(subst sdk,open-api/typescript-sdk,$*) run build || true
|
||||
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) run build
|
||||
format-%:
|
||||
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) run | grep 'format:fix' >/dev/null \
|
||||
&& npm --prefix $(subst sdk,open-api/typescript-sdk,$*) run format:fix || true
|
||||
npm --prefix $* run format:fix
|
||||
lint-%:
|
||||
npm --prefix $* run lint:fix
|
||||
check-%:
|
||||
@@ -79,14 +77,14 @@ test-medium:
|
||||
test-medium-dev:
|
||||
docker exec -it immich_server /bin/sh -c "npm run test:medium"
|
||||
|
||||
build-all: $(foreach M,$(MODULES),build-$M) ;
|
||||
build-all: $(foreach M,$(filter-out e2e,$(MODULES)),build-$M) ;
|
||||
install-all: $(foreach M,$(MODULES),install-$M) ;
|
||||
check-all: $(foreach M,$(MODULES),check-$M) ;
|
||||
lint-all: $(foreach M,$(MODULES),lint-$M) ;
|
||||
format-all: $(foreach M,$(MODULES),format-$M) ;
|
||||
check-all: $(foreach M,$(filter-out sdk cli docs,$(MODULES)),check-$M) ;
|
||||
lint-all: $(foreach M,$(filter-out sdk docs,$(MODULES)),lint-$M) ;
|
||||
format-all: $(foreach M,$(filter-out sdk,$(MODULES)),format-$M) ;
|
||||
audit-all: $(foreach M,$(MODULES),audit-$M) ;
|
||||
hygiene-all: lint-all format-all check-all sql audit-all;
|
||||
test-all: $(foreach M,$(MODULES),test-$M) ;
|
||||
test-all: $(foreach M,$(filter-out sdk docs,$(MODULES)),test-$M) ;
|
||||
|
||||
clean:
|
||||
find . -name "node_modules" -type d -prune -exec rm -rf '{}' +
|
||||
|
||||
36
README.md
@@ -17,24 +17,24 @@
|
||||
<img src="design/immich-screenshots.png" title="Main Screenshot">
|
||||
</a>
|
||||
<br/>
|
||||
|
||||
<p align="center">
|
||||
|
||||
<a href="readme_i18n/README_ca_ES.md">Català</a>
|
||||
<a href="readme_i18n/README_es_ES.md">Español</a>
|
||||
<a href="readme_i18n/README_fr_FR.md">Français</a>
|
||||
<a href="readme_i18n/README_it_IT.md">Italiano</a>
|
||||
<a href="readme_i18n/README_ja_JP.md">日本語</a>
|
||||
<a href="readme_i18n/README_ko_KR.md">한국어</a>
|
||||
<a href="readme_i18n/README_de_DE.md">Deutsch</a>
|
||||
<a href="readme_i18n/README_nl_NL.md">Nederlands</a>
|
||||
<a href="readme_i18n/README_tr_TR.md">Türkçe</a>
|
||||
<a href="readme_i18n/README_zh_CN.md">中文</a>
|
||||
<a href="readme_i18n/README_ru_RU.md">Русский</a>
|
||||
<a href="readme_i18n/README_pt_BR.md">Português Brasileiro</a>
|
||||
<a href="readme_i18n/README_sv_SE.md">Svenska</a>
|
||||
<a href="readme_i18n/README_ar_JO.md">العربية</a>
|
||||
<a href="readme_i18n/README_vi_VN.md">Tiếng Việt</a>
|
||||
|
||||
<a href="readme_i18n/README_ca_ES.md">Català</a>
|
||||
<a href="readme_i18n/README_es_ES.md">Español</a>
|
||||
<a href="readme_i18n/README_fr_FR.md">Français</a>
|
||||
<a href="readme_i18n/README_it_IT.md">Italiano</a>
|
||||
<a href="readme_i18n/README_ja_JP.md">日本語</a>
|
||||
<a href="readme_i18n/README_ko_KR.md">한국어</a>
|
||||
<a href="readme_i18n/README_de_DE.md">Deutsch</a>
|
||||
<a href="readme_i18n/README_nl_NL.md">Nederlands</a>
|
||||
<a href="readme_i18n/README_tr_TR.md">Türkçe</a>
|
||||
<a href="readme_i18n/README_zh_CN.md">中文</a>
|
||||
<a href="readme_i18n/README_ru_RU.md">Русский</a>
|
||||
<a href="readme_i18n/README_pt_BR.md">Português Brasileiro</a>
|
||||
<a href="readme_i18n/README_sv_SE.md">Svenska</a>
|
||||
<a href="readme_i18n/README_ar_JO.md">العربية</a>
|
||||
<a href="readme_i18n/README_vi_VN.md">Tiếng Việt</a>
|
||||
<a href="readme_i18n/README_th_TH.md">ภาษาไทย</a>
|
||||
</p>
|
||||
|
||||
## Disclaimer
|
||||
@@ -102,6 +102,8 @@ For the mobile app, you can use `https://demo.immich.app/api` for the `Server En
|
||||
| Offline support | Yes | No |
|
||||
| Read-only gallery | Yes | Yes |
|
||||
| Stacked Photos | Yes | Yes |
|
||||
| Tags | No | Yes |
|
||||
| Folder View | No | Yes |
|
||||
|
||||
## Translations
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
20.18.0
|
||||
22.11.0
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM node:20.17.0-alpine3.20@sha256:2d07db07a2df6830718ae2a47db6fedce6745f5bcd174c398f2acdda90a11c03 AS core
|
||||
FROM node:22.11.0-alpine3.20@sha256:dc8ba2f61dd86c44e43eb25a7812ad03c5b1b224a19fc6f77e1eb9e5669f0b82 AS core
|
||||
|
||||
WORKDIR /usr/src/open-api/typescript-sdk
|
||||
COPY open-api/typescript-sdk/package*.json open-api/typescript-sdk/tsconfig*.json ./
|
||||
|
||||
534
cli/package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@immich/cli",
|
||||
"version": "2.2.23",
|
||||
"version": "2.2.32",
|
||||
"description": "Command Line Interface (CLI) for Immich",
|
||||
"type": "module",
|
||||
"exports": "./dist/index.js",
|
||||
@@ -20,7 +20,7 @@
|
||||
"@types/cli-progress": "^3.11.0",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/mock-fs": "^4.13.1",
|
||||
"@types/node": "^20.16.10",
|
||||
"@types/node": "^22.9.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
||||
"@typescript-eslint/parser": "^8.0.0",
|
||||
"@vitest/coverage-v8": "^2.0.5",
|
||||
@@ -39,7 +39,7 @@
|
||||
"vite": "^5.0.12",
|
||||
"vite-tsconfig-paths": "^5.0.0",
|
||||
"vitest": "^2.0.5",
|
||||
"vitest-fetch-mock": "^0.3.0",
|
||||
"vitest-fetch-mock": "^0.4.0",
|
||||
"yaml": "^2.3.1"
|
||||
},
|
||||
"scripts": {
|
||||
@@ -67,6 +67,6 @@
|
||||
"lodash-es": "^4.17.21"
|
||||
},
|
||||
"volta": {
|
||||
"node": "20.18.0"
|
||||
"node": "22.11.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
Action,
|
||||
AssetBulkUploadCheckItem,
|
||||
AssetBulkUploadCheckResult,
|
||||
AssetMediaResponseDto,
|
||||
AssetMediaStatus,
|
||||
@@ -11,7 +12,7 @@ import {
|
||||
getSupportedMediaTypes,
|
||||
} from '@immich/sdk';
|
||||
import byteSize from 'byte-size';
|
||||
import { Presets, SingleBar } from 'cli-progress';
|
||||
import { MultiBar, Presets, SingleBar } from 'cli-progress';
|
||||
import { chunk } from 'lodash-es';
|
||||
import { Stats, createReadStream } from 'node:fs';
|
||||
import { stat, unlink } from 'node:fs/promises';
|
||||
@@ -90,23 +91,23 @@ export const checkForDuplicates = async (files: string[], { concurrency, skipHas
|
||||
return { newFiles: files, duplicates: [] };
|
||||
}
|
||||
|
||||
const progressBar = new SingleBar(
|
||||
{ format: 'Checking files | {bar} | {percentage}% | ETA: {eta}s | {value}/{total} assets' },
|
||||
const multiBar = new MultiBar(
|
||||
{ format: '{message} | {bar} | {percentage}% | ETA: {eta}s | {value}/{total} assets' },
|
||||
Presets.shades_classic,
|
||||
);
|
||||
|
||||
progressBar.start(files.length, 0);
|
||||
const hashProgressBar = multiBar.create(files.length, 0, { message: 'Hashing files ' });
|
||||
const checkProgressBar = multiBar.create(files.length, 0, { message: 'Checking for duplicates' });
|
||||
|
||||
const newFiles: string[] = [];
|
||||
const duplicates: Asset[] = [];
|
||||
|
||||
const queue = new Queue<string[], AssetBulkUploadCheckResults>(
|
||||
async (filepaths: string[]) => {
|
||||
const dto = await Promise.all(
|
||||
filepaths.map(async (filepath) => ({ id: filepath, checksum: await sha1(filepath) })),
|
||||
);
|
||||
const response = await checkBulkUpload({ assetBulkUploadCheckDto: { assets: dto } });
|
||||
const checkBulkUploadQueue = new Queue<AssetBulkUploadCheckItem[], void>(
|
||||
async (assets: AssetBulkUploadCheckItem[]) => {
|
||||
const response = await checkBulkUpload({ assetBulkUploadCheckDto: { assets } });
|
||||
|
||||
const results = response.results as AssetBulkUploadCheckResults;
|
||||
|
||||
for (const { id: filepath, assetId, action } of results) {
|
||||
if (action === Action.Accept) {
|
||||
newFiles.push(filepath);
|
||||
@@ -115,19 +116,46 @@ export const checkForDuplicates = async (files: string[], { concurrency, skipHas
|
||||
duplicates.push({ id: assetId as string, filepath });
|
||||
}
|
||||
}
|
||||
progressBar.increment(filepaths.length);
|
||||
|
||||
checkProgressBar.increment(assets.length);
|
||||
},
|
||||
{ concurrency, retry: 3 },
|
||||
);
|
||||
|
||||
const results: { id: string; checksum: string }[] = [];
|
||||
let checkBulkUploadRequests: AssetBulkUploadCheckItem[] = [];
|
||||
|
||||
const queue = new Queue<string, AssetBulkUploadCheckItem[]>(
|
||||
async (filepath: string): Promise<AssetBulkUploadCheckItem[]> => {
|
||||
const dto = { id: filepath, checksum: await sha1(filepath) };
|
||||
|
||||
results.push(dto);
|
||||
checkBulkUploadRequests.push(dto);
|
||||
if (checkBulkUploadRequests.length === 5000) {
|
||||
const batch = checkBulkUploadRequests;
|
||||
checkBulkUploadRequests = [];
|
||||
void checkBulkUploadQueue.push(batch);
|
||||
}
|
||||
|
||||
hashProgressBar.increment();
|
||||
return results;
|
||||
},
|
||||
{ concurrency, retry: 3 },
|
||||
);
|
||||
|
||||
for (const items of chunk(files, concurrency)) {
|
||||
await queue.push(items);
|
||||
for (const item of files) {
|
||||
void queue.push(item);
|
||||
}
|
||||
|
||||
await queue.drained();
|
||||
|
||||
progressBar.stop();
|
||||
if (checkBulkUploadRequests.length > 0) {
|
||||
void checkBulkUploadQueue.push(checkBulkUploadRequests);
|
||||
}
|
||||
|
||||
await checkBulkUploadQueue.drained();
|
||||
|
||||
multiBar.stop();
|
||||
|
||||
console.log(`Found ${newFiles.length} new files and ${duplicates.length} duplicate${s(duplicates.length)}`);
|
||||
|
||||
@@ -201,8 +229,8 @@ export const uploadFiles = async (files: string[], { dryRun, concurrency }: Uplo
|
||||
{ concurrency, retry: 3 },
|
||||
);
|
||||
|
||||
for (const filepath of files) {
|
||||
await queue.push(filepath);
|
||||
for (const item of files) {
|
||||
void queue.push(item);
|
||||
}
|
||||
|
||||
await queue.drained();
|
||||
|
||||
@@ -72,8 +72,8 @@ export class Queue<T, R> {
|
||||
* @returns Promise<void> - The returned Promise will be resolved when all tasks in the queue have been processed by a worker.
|
||||
* This promise could be ignored as it will not lead to a `unhandledRejection`.
|
||||
*/
|
||||
async drained(): Promise<void> {
|
||||
await this.queue.drain();
|
||||
drained(): Promise<void> {
|
||||
return this.queue.drained();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,37 +2,37 @@
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.opentofu.org/cloudflare/cloudflare" {
|
||||
version = "4.43.0"
|
||||
constraints = "4.43.0"
|
||||
version = "4.46.0"
|
||||
constraints = "4.46.0"
|
||||
hashes = [
|
||||
"h1:2kDVLD36BOVgBzI9p0WIQ+xjFfMmjaItA0l8SyZWEPo=",
|
||||
"h1:2sGJDAwFEgO8+3y+2suYO+yrjNOzSsihad0hbM3+jPg=",
|
||||
"h1:A1WPQFcdD+7FrFBFrKcx4CiSr75xSmsO93C0e5NBAeQ=",
|
||||
"h1:BuXs/1ohmF4fWyOErY6vNbm7DaEIfbLSepSiZ2ol9I8=",
|
||||
"h1:QPh+X19oyo808sqdeJaVqahZcQgcG1jCi3DA5zpjz6U=",
|
||||
"h1:RI7c7dhSJoIkfou5b8ITRpM5MqsQD3FULj1h/rI4rJk=",
|
||||
"h1:gdI5JTCPjewdGq1bhGAs+V5qCcmJ73N2gtMfuFybJp4=",
|
||||
"h1:h4lnJpCIYZ7dsN9IO2mmwNdWNiQYEPoAEUjLF2sZ5kc=",
|
||||
"h1:jTaExrX/eR7vGT5wayGqH8ZtXS2zyk0WmD3zbAKFIQU=",
|
||||
"h1:l5NKJUOQJ1mHl1eekeXaxUZ+g+8Yv4aGcIN9vuK6GL4=",
|
||||
"h1:sNbvm66/2vc8B/khyioOO8eNaU8nb89x693AN7fQheU=",
|
||||
"h1:tXS4g1yE420AU4mvZ7RrYI+yYTutkRID3l+W0gBH4BM=",
|
||||
"h1:vA+kES7uqmKA9K0U45IXR94jaTQZCHZLCHqMUeGxKMI=",
|
||||
"h1:zV131k79+ob9p4jrLDgztDNvZvt8fvrrzpn0nPikBw8=",
|
||||
"zh:006d111d6eafe6eeb5df2f91bd0ca320f979bd71f8cd8c475f10b2bd94acba55",
|
||||
"zh:031fbb5cac23a841dc18e270cbfcd3ce9f4ba504edbd3c78931f7ed9827220a8",
|
||||
"zh:07a72fe8b55afee99529bf4169ab6abfac5eabcd10968c29101925bcd358b09f",
|
||||
"zh:0d14727d011c2d9df4c3058f527d2409223449ab48b46cbc86922eb553ef77c1",
|
||||
"zh:155ce1333672d26cd18a5866b0761489d91682beffee58e45c3a1b68e8491d3d",
|
||||
"zh:35a2a1939a965335b29ebdbfd759d93a97c0f589d9cd218f537dee6f600e3fb9",
|
||||
"zh:52912fe421e7d911431f77788db2ea13836efd65a2e82385adb52c6a84d4ee90",
|
||||
"zh:57374318d9194ea1db08884b0541a9055823d5970ad48f9a57547ac231163007",
|
||||
"zh:5fb942b9e2553c058fe09fe12fb39dd175cd6715bb41c059c1a70df2bfc64dc1",
|
||||
"zh:63cabd2bda201b09b35a3279d1f813ab71394b9b90fc5cf8962a5eba207803bc",
|
||||
"h1:3U4N3bbMacXTAdyaEwT305kETMETh1jZmGApmN6gdyE=",
|
||||
"h1:3fhZhGNgtS9ugcZ2CIH6kk8LzN6yPxqOdkDUZqkP3+w=",
|
||||
"h1:JWluJxBRSr8GVUhWVv83xse9SmbpwCLctCDddMXUnVk=",
|
||||
"h1:KDHwakGt+3iBKXaoALCCAolPaJgpEHbkh3BfjnpuqoM=",
|
||||
"h1:QFFZshAvwr9L5TQmsNQC6/sDqokk5pjbP8Ae4BQqMLQ=",
|
||||
"h1:Qdi+vXwzDNii7ytSaOQtnlqhjZ3ZlRoUkFoi6CD2COI=",
|
||||
"h1:TPcJXcVb/+C91hUuu8CEn98QUoNgLtnHfd4sgAOV+5k=",
|
||||
"h1:WDy5wiNroXaCnw+r8rJnCP+J1RVsm2Qu3AOZ/iV4lLo=",
|
||||
"h1:hMuL+dwHj3JbePqYcDrn/ZQN9R0WzeJX0AIDJ02Iteo=",
|
||||
"h1:hQKCaUEARzJKbFt1CePP06E/+CiHWe/H6lc1AwK7y6w=",
|
||||
"h1:l4DQ3WXmSzR/GBel3m2CRKWtaziVjBoxvUgL63t1GK0=",
|
||||
"h1:nN9uVSLyrb/DjfZl6rPtCq5j0TX+6WypzNDexdzCQ08=",
|
||||
"h1:rAX7njl6lKT9XIKMk6pLjVi7u/42wafRolWWgMHMkI0=",
|
||||
"h1:t2IQYNu8YNykqYlEB+TTX+XpUd5z2flwGw8km9UgbnQ=",
|
||||
"zh:2ee426ef3389022db0026792fdc4f2980dcf2600e31adf5a31b4bddfa8d68343",
|
||||
"zh:2f993edb23df55dc1c18150fa187d80aa7d87e6439698ee34b6a6aad23ac2dd7",
|
||||
"zh:3d6601333975e55979b1b454e50ff9a482ce4e0269dd6c72a50202163a8f4463",
|
||||
"zh:4e5f48dce22f7a6d618018d65d1d443bb718defa23f514d5c6385860541fbe79",
|
||||
"zh:5ebf5aea960fc30de381ffd6db20876d249673cf938fe67f1dfb6b9caa1db418",
|
||||
"zh:80ed3fb901141f53b4b56ddb7eea5f2e0c0830d501387539d2c2b8e0cc7e587a",
|
||||
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
|
||||
"zh:978ee67d3d53970a5c474ab40b00adee97f4153b16804a2b6b7ee205ae69d18a",
|
||||
"zh:bbafdbef631b5c80570087817b42b16b1a76d556d692853a71c47fb48663cf00",
|
||||
"zh:be91b3f2a697cbbb41f65aad2600972d0ede1e962a7d8a00bb3177cb77d86666",
|
||||
"zh:efe168ad4aaa6156ce5a31d4e50e9d54d38ee5a5888412f9e690c0de5d619683",
|
||||
"zh:9aeae8b3be4a577ced46987fd9159262c5b4c54a510f66592fbcdb40fef55b10",
|
||||
"zh:a0479ef2d308c4a7894f1fe77467cd07e04c7b40d281088f4f204af1bdf94ac6",
|
||||
"zh:a2bdc0c25130665af0b9559942b9813a1ba4889513e7185d4abc9c02e9bb99bd",
|
||||
"zh:b10be9755fe80395ced6f0bbda38b8c8681714cf1eca1d895be239c75c2ffc2a",
|
||||
"zh:ba3d55e722d9f48646574ce7c448f0084fe21fa884b5f8b6d6146a82a99c4baa",
|
||||
"zh:ec1fd0ecaedc787a77d5342b51ae8dea8362a67f1e19123f6521a0e8e012d9e8",
|
||||
"zh:ed49590e69faef14550179f965b4451b31415b8f6be6d33427ad48f65c76b6cf",
|
||||
"zh:f4baa3a2dac719ad20dcfa525bc3f737ad95650b8d0de0c648dc9a87f993b2c3",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ terraform {
|
||||
required_providers {
|
||||
cloudflare = {
|
||||
source = "cloudflare/cloudflare"
|
||||
version = "4.43.0"
|
||||
version = "4.46.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,37 +2,37 @@
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.opentofu.org/cloudflare/cloudflare" {
|
||||
version = "4.43.0"
|
||||
constraints = "4.43.0"
|
||||
version = "4.46.0"
|
||||
constraints = "4.46.0"
|
||||
hashes = [
|
||||
"h1:2kDVLD36BOVgBzI9p0WIQ+xjFfMmjaItA0l8SyZWEPo=",
|
||||
"h1:2sGJDAwFEgO8+3y+2suYO+yrjNOzSsihad0hbM3+jPg=",
|
||||
"h1:A1WPQFcdD+7FrFBFrKcx4CiSr75xSmsO93C0e5NBAeQ=",
|
||||
"h1:BuXs/1ohmF4fWyOErY6vNbm7DaEIfbLSepSiZ2ol9I8=",
|
||||
"h1:QPh+X19oyo808sqdeJaVqahZcQgcG1jCi3DA5zpjz6U=",
|
||||
"h1:RI7c7dhSJoIkfou5b8ITRpM5MqsQD3FULj1h/rI4rJk=",
|
||||
"h1:gdI5JTCPjewdGq1bhGAs+V5qCcmJ73N2gtMfuFybJp4=",
|
||||
"h1:h4lnJpCIYZ7dsN9IO2mmwNdWNiQYEPoAEUjLF2sZ5kc=",
|
||||
"h1:jTaExrX/eR7vGT5wayGqH8ZtXS2zyk0WmD3zbAKFIQU=",
|
||||
"h1:l5NKJUOQJ1mHl1eekeXaxUZ+g+8Yv4aGcIN9vuK6GL4=",
|
||||
"h1:sNbvm66/2vc8B/khyioOO8eNaU8nb89x693AN7fQheU=",
|
||||
"h1:tXS4g1yE420AU4mvZ7RrYI+yYTutkRID3l+W0gBH4BM=",
|
||||
"h1:vA+kES7uqmKA9K0U45IXR94jaTQZCHZLCHqMUeGxKMI=",
|
||||
"h1:zV131k79+ob9p4jrLDgztDNvZvt8fvrrzpn0nPikBw8=",
|
||||
"zh:006d111d6eafe6eeb5df2f91bd0ca320f979bd71f8cd8c475f10b2bd94acba55",
|
||||
"zh:031fbb5cac23a841dc18e270cbfcd3ce9f4ba504edbd3c78931f7ed9827220a8",
|
||||
"zh:07a72fe8b55afee99529bf4169ab6abfac5eabcd10968c29101925bcd358b09f",
|
||||
"zh:0d14727d011c2d9df4c3058f527d2409223449ab48b46cbc86922eb553ef77c1",
|
||||
"zh:155ce1333672d26cd18a5866b0761489d91682beffee58e45c3a1b68e8491d3d",
|
||||
"zh:35a2a1939a965335b29ebdbfd759d93a97c0f589d9cd218f537dee6f600e3fb9",
|
||||
"zh:52912fe421e7d911431f77788db2ea13836efd65a2e82385adb52c6a84d4ee90",
|
||||
"zh:57374318d9194ea1db08884b0541a9055823d5970ad48f9a57547ac231163007",
|
||||
"zh:5fb942b9e2553c058fe09fe12fb39dd175cd6715bb41c059c1a70df2bfc64dc1",
|
||||
"zh:63cabd2bda201b09b35a3279d1f813ab71394b9b90fc5cf8962a5eba207803bc",
|
||||
"h1:3U4N3bbMacXTAdyaEwT305kETMETh1jZmGApmN6gdyE=",
|
||||
"h1:3fhZhGNgtS9ugcZ2CIH6kk8LzN6yPxqOdkDUZqkP3+w=",
|
||||
"h1:JWluJxBRSr8GVUhWVv83xse9SmbpwCLctCDddMXUnVk=",
|
||||
"h1:KDHwakGt+3iBKXaoALCCAolPaJgpEHbkh3BfjnpuqoM=",
|
||||
"h1:QFFZshAvwr9L5TQmsNQC6/sDqokk5pjbP8Ae4BQqMLQ=",
|
||||
"h1:Qdi+vXwzDNii7ytSaOQtnlqhjZ3ZlRoUkFoi6CD2COI=",
|
||||
"h1:TPcJXcVb/+C91hUuu8CEn98QUoNgLtnHfd4sgAOV+5k=",
|
||||
"h1:WDy5wiNroXaCnw+r8rJnCP+J1RVsm2Qu3AOZ/iV4lLo=",
|
||||
"h1:hMuL+dwHj3JbePqYcDrn/ZQN9R0WzeJX0AIDJ02Iteo=",
|
||||
"h1:hQKCaUEARzJKbFt1CePP06E/+CiHWe/H6lc1AwK7y6w=",
|
||||
"h1:l4DQ3WXmSzR/GBel3m2CRKWtaziVjBoxvUgL63t1GK0=",
|
||||
"h1:nN9uVSLyrb/DjfZl6rPtCq5j0TX+6WypzNDexdzCQ08=",
|
||||
"h1:rAX7njl6lKT9XIKMk6pLjVi7u/42wafRolWWgMHMkI0=",
|
||||
"h1:t2IQYNu8YNykqYlEB+TTX+XpUd5z2flwGw8km9UgbnQ=",
|
||||
"zh:2ee426ef3389022db0026792fdc4f2980dcf2600e31adf5a31b4bddfa8d68343",
|
||||
"zh:2f993edb23df55dc1c18150fa187d80aa7d87e6439698ee34b6a6aad23ac2dd7",
|
||||
"zh:3d6601333975e55979b1b454e50ff9a482ce4e0269dd6c72a50202163a8f4463",
|
||||
"zh:4e5f48dce22f7a6d618018d65d1d443bb718defa23f514d5c6385860541fbe79",
|
||||
"zh:5ebf5aea960fc30de381ffd6db20876d249673cf938fe67f1dfb6b9caa1db418",
|
||||
"zh:80ed3fb901141f53b4b56ddb7eea5f2e0c0830d501387539d2c2b8e0cc7e587a",
|
||||
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
|
||||
"zh:978ee67d3d53970a5c474ab40b00adee97f4153b16804a2b6b7ee205ae69d18a",
|
||||
"zh:bbafdbef631b5c80570087817b42b16b1a76d556d692853a71c47fb48663cf00",
|
||||
"zh:be91b3f2a697cbbb41f65aad2600972d0ede1e962a7d8a00bb3177cb77d86666",
|
||||
"zh:efe168ad4aaa6156ce5a31d4e50e9d54d38ee5a5888412f9e690c0de5d619683",
|
||||
"zh:9aeae8b3be4a577ced46987fd9159262c5b4c54a510f66592fbcdb40fef55b10",
|
||||
"zh:a0479ef2d308c4a7894f1fe77467cd07e04c7b40d281088f4f204af1bdf94ac6",
|
||||
"zh:a2bdc0c25130665af0b9559942b9813a1ba4889513e7185d4abc9c02e9bb99bd",
|
||||
"zh:b10be9755fe80395ced6f0bbda38b8c8681714cf1eca1d895be239c75c2ffc2a",
|
||||
"zh:ba3d55e722d9f48646574ce7c448f0084fe21fa884b5f8b6d6146a82a99c4baa",
|
||||
"zh:ec1fd0ecaedc787a77d5342b51ae8dea8362a67f1e19123f6521a0e8e012d9e8",
|
||||
"zh:ed49590e69faef14550179f965b4451b31415b8f6be6d33427ad48f65c76b6cf",
|
||||
"zh:f4baa3a2dac719ad20dcfa525bc3f737ad95650b8d0de0c648dc9a87f993b2c3",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ terraform {
|
||||
required_providers {
|
||||
cloudflare = {
|
||||
source = "cloudflare/cloudflare"
|
||||
version = "4.43.0"
|
||||
version = "4.46.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +66,7 @@ services:
|
||||
- 24678:24678
|
||||
volumes:
|
||||
- ../web:/usr/src/app
|
||||
- ../i18n:/usr/src/i18n
|
||||
- ../open-api/:/usr/src/open-api/
|
||||
- /usr/src/app/node_modules
|
||||
ulimits:
|
||||
@@ -102,7 +103,7 @@ services:
|
||||
|
||||
redis:
|
||||
container_name: immich_redis
|
||||
image: redis:6.2-alpine@sha256:2ba50e1ac3a0ea17b736ce9db2b0a9f6f8b85d4c27d5f5accc6a416d8f42c6d5
|
||||
image: redis:6.2-alpine@sha256:eaba718fecd1196d88533de7ba49bf903ad33664a92debb24660a922ecd9cac8
|
||||
healthcheck:
|
||||
test: redis-cli ping || exit 1
|
||||
|
||||
@@ -142,7 +143,7 @@ services:
|
||||
'wal_compression=on',
|
||||
]
|
||||
|
||||
# set IMMICH_METRICS=true in .env to enable metrics
|
||||
# set IMMICH_TELEMETRY_INCLUDE=all in .env to enable metrics
|
||||
# immich-prometheus:
|
||||
# container_name: immich_prometheus
|
||||
# ports:
|
||||
|
||||
@@ -47,7 +47,7 @@ services:
|
||||
|
||||
redis:
|
||||
container_name: immich_redis
|
||||
image: redis:6.2-alpine@sha256:2ba50e1ac3a0ea17b736ce9db2b0a9f6f8b85d4c27d5f5accc6a416d8f42c6d5
|
||||
image: redis:6.2-alpine@sha256:eaba718fecd1196d88533de7ba49bf903ad33664a92debb24660a922ecd9cac8
|
||||
healthcheck:
|
||||
test: redis-cli ping || exit 1
|
||||
restart: always
|
||||
@@ -89,12 +89,12 @@ services:
|
||||
]
|
||||
restart: always
|
||||
|
||||
# set IMMICH_METRICS=true in .env to enable metrics
|
||||
# set IMMICH_TELEMETRY_INCLUDE=all in .env to enable metrics
|
||||
immich-prometheus:
|
||||
container_name: immich_prometheus
|
||||
ports:
|
||||
- 9090:9090
|
||||
image: prom/prometheus@sha256:f6639335d34a77d9d9db382b92eeb7fc00934be8eae81dbc03b31cfe90411a94
|
||||
image: prom/prometheus@sha256:3b9b2a15d376334da8c286d995777d3b9315aa666d2311170ada6059a517b74f
|
||||
volumes:
|
||||
- ./prometheus.yml:/etc/prometheus/prometheus.yml
|
||||
- prometheus-data:/prometheus
|
||||
@@ -106,7 +106,7 @@ services:
|
||||
command: ['./run.sh', '-disable-reporting']
|
||||
ports:
|
||||
- 3000:3000
|
||||
image: grafana/grafana:11.2.2-ubuntu@sha256:2bef00403c18d27919ff19d64fd6253fa713b3880304e92f69109e14221ac843
|
||||
image: grafana/grafana:11.3.0-ubuntu@sha256:51587e148ac0214d7938e7f3fe8512182e4eb6141892a3ffb88bba1901b49285
|
||||
volumes:
|
||||
- grafana-data:/var/lib/grafana
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ services:
|
||||
|
||||
redis:
|
||||
container_name: immich_redis
|
||||
image: docker.io/redis:6.2-alpine@sha256:2ba50e1ac3a0ea17b736ce9db2b0a9f6f8b85d4c27d5f5accc6a416d8f42c6d5
|
||||
image: docker.io/redis:6.2-alpine@sha256:eaba718fecd1196d88533de7ba49bf903ad33664a92debb24660a922ecd9cac8
|
||||
healthcheck:
|
||||
test: redis-cli ping || exit 1
|
||||
restart: always
|
||||
|
||||
@@ -1 +1 @@
|
||||
20.18.0
|
||||
22.11.0
|
||||
|
||||
@@ -15,12 +15,21 @@ Immich saves [file paths in the database](https://github.com/immich-app/immich/d
|
||||
Refer to the official [postgres documentation](https://www.postgresql.org/docs/current/backup.html) for details about backing up and restoring a postgres database.
|
||||
:::
|
||||
|
||||
The recommended way to backup and restore the Immich database is to use the `pg_dumpall` command. When restoring, you need to delete the `DB_DATA_LOCATION` folder (if it exists) to reset the database.
|
||||
|
||||
:::caution
|
||||
It is not recommended to directly backup the `DB_DATA_LOCATION` folder. Doing so while the database is running can lead to a corrupted backup that cannot be restored.
|
||||
:::
|
||||
|
||||
### Automatic Database Backups
|
||||
|
||||
Immich will automatically create database backups by default. The backups are stored in `UPLOAD_LOCATION/backups`.
|
||||
You can adjust the schedule and amount of kept backups in the [admin settings](http://my.immich.app/admin/system-settings?isOpen=backup).
|
||||
By default, Immich will keep the last 14 backups and create a new backup every day at 2:00 AM.
|
||||
|
||||
#### Restoring
|
||||
|
||||
We hope to make restoring simpler in future versions, for now you can find the backups in the `UPLOAD_LOCATION/backups` folder on your host.
|
||||
Then please follow the steps in the following section for restoring the database.
|
||||
|
||||
### Manual Backup and Restore
|
||||
|
||||
<Tabs>
|
||||
@@ -49,7 +58,7 @@ docker compose up -d # Start remainder of Immich apps
|
||||
<TabItem value="Windows system (PowerShell)" label="Windows system (PowerShell)">
|
||||
|
||||
```powershell title='Backup'
|
||||
docker exec -t immich_postgres pg_dumpall --clean --if-exists --username=postgres | Set-Content -Encoding utf8 "C:\path\to\backup\dump.sql"
|
||||
[System.IO.File]::WriteAllLines("C:\absolute\path\to\backup\dump.sql", (docker exec -t immich_postgres pg_dumpall --clean --if-exists --username=postgres))
|
||||
```
|
||||
|
||||
```powershell title='Restore'
|
||||
@@ -68,53 +77,10 @@ docker compose up -d # Start remainder of Immich apps
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
Note that for the database restore to proceed properly, it requires a completely fresh install (i.e. the Immich server has never run since creating the Docker containers). If the Immich app has run, Postgres conflicts may be encountered upon database restoration (relation already exists, violated foreign key constraints, multiple primary keys, etc.).
|
||||
Note that for the database restore to proceed properly, it requires a completely fresh install (i.e. the Immich server has never run since creating the Docker containers). If the Immich app has run, Postgres conflicts may be encountered upon database restoration (relation already exists, violated foreign key constraints, multiple primary keys, etc.), in which case you need to delete the `DB_DATA_LOCATION` folder to reset the database.
|
||||
|
||||
:::tip
|
||||
Some deployment methods make it difficult to start the database without also starting the server or microservices. In these cases, you may set the environmental variable `DB_SKIP_MIGRATIONS=true` before starting the services. This will prevent the server from running migrations that interfere with the restore process. Note that both the server and microservices must have this variable set to prevent the migrations from running. Be sure to remove this variable and restart the services after the database is restored.
|
||||
:::
|
||||
|
||||
### Automatic Database Backups
|
||||
|
||||
The database dumps can also be automated (using [this image](https://github.com/prodrigestivill/docker-postgres-backup-local)) by editing the docker compose file to match the following:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
...
|
||||
backup:
|
||||
container_name: immich_db_dumper
|
||||
image: prodrigestivill/postgres-backup-local:14
|
||||
restart: always
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
POSTGRES_HOST: database
|
||||
POSTGRES_CLUSTER: 'TRUE'
|
||||
POSTGRES_USER: ${DB_USERNAME}
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||||
POSTGRES_DB: ${DB_DATABASE_NAME}
|
||||
SCHEDULE: "@daily"
|
||||
POSTGRES_EXTRA_OPTS: '--clean --if-exists'
|
||||
BACKUP_DIR: /db_dumps
|
||||
volumes:
|
||||
- ./db_dumps:/db_dumps
|
||||
depends_on:
|
||||
- database
|
||||
```
|
||||
|
||||
Then you can restore with the same command but pointed at the latest dump.
|
||||
|
||||
```bash title='Automated Restore'
|
||||
# Be sure to check the username if you changed it from default
|
||||
gunzip < db_dumps/last/immich-latest.sql.gz \
|
||||
| sed "s/SELECT pg_catalog.set_config('search_path', '', false);/SELECT pg_catalog.set_config('search_path', 'public, pg_catalog', true);/g" \
|
||||
| docker exec -i immich_postgres psql --username=postgres
|
||||
```
|
||||
|
||||
:::note
|
||||
If you see the error `ERROR: type "earth" does not exist`, or you have problems with Reverse Geocoding after a restore, add the following `sed` fragment to your restore command.
|
||||
|
||||
Example: `gunzip < "/path/to/backup/dump.sql.gz" | sed "s/SELECT pg_catalog.set_config('search_path', '', false);/SELECT pg_catalog.set_config('search_path', 'public, pg_catalog', true);/g" | docker exec -i immich_postgres psql --username=postgres`
|
||||
Some deployment methods make it difficult to start the database without also starting the server. In these cases, you may set the environment variable `DB_SKIP_MIGRATIONS=true` before starting the services. This will prevent the server from running migrations that interfere with the restore process. Be sure to remove this variable and restart the services after the database is restored.
|
||||
:::
|
||||
|
||||
## Filesystem
|
||||
@@ -200,7 +166,7 @@ When you turn off the storage template engine, it will leave the assets in `UPLO
|
||||
- Stored in `UPLOAD_LOCATION/profile/<userID>`.
|
||||
- **Thumbs Images:**
|
||||
- Preview images (blurred, small, large) for each asset and thumbnails for recognized faces.
|
||||
- Stored in `UPLOCAD_LOCATION/thumbs/<userID>`.
|
||||
- Stored in `UPLOAD_LOCATION/thumbs/<userID>`.
|
||||
- **Encoded Assets:**
|
||||
- Videos that have been re-encoded from the original for wider compatibility. The original is not removed.
|
||||
- Stored in `UPLOAD_LOCATION/encoded-video/<userID>`.
|
||||
|
||||
@@ -11,7 +11,7 @@ Unable to set `app.immich:///oauth-callback` as a valid redirect URI? See [Mobil
|
||||
Immich supports 3rd party authentication via [OpenID Connect][oidc] (OIDC), an identity layer built on top of OAuth2. OIDC is supported by most identity providers, including:
|
||||
|
||||
- [Authentik](https://goauthentik.io/integrations/sources/oauth/#openid-connect)
|
||||
- [Authelia](https://www.authelia.com/configuration/identity-providers/openid-connect/clients/)
|
||||
- [Authelia](https://www.authelia.com/integration/openid-connect/immich/)
|
||||
- [Okta](https://www.okta.com/openid-connect/)
|
||||
- [Google](https://developers.google.com/identity/openid-connect/openid-connect)
|
||||
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# Repair Page
|
||||
|
||||
:::warning
|
||||
This feature is currently disabled and will be reworked in the near future.
|
||||
:::
|
||||
|
||||
The repair page is designed to give information to the system administrator about files that are not tracked, or offline paths.
|
||||
|
||||
## Natural State
|
||||
|
||||
@@ -40,6 +40,26 @@ server {
|
||||
}
|
||||
```
|
||||
|
||||
#### Compatibility with Let's Encrypt
|
||||
|
||||
In the event that your nginx configuration includes a section for Let's Encrypt, it's likely that you have a segment similar to the following:
|
||||
|
||||
```nginx
|
||||
location ~ /.well-known {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
This particular `location` directive can inadvertently prevent mobile clients from reaching the `/.well-known/immich` path, which is crucial for discovery. Usual error message for this case is: "Your app major version is not compatible with the server". To remedy this, you should introduce an additional location block specifically for this path, ensuring that requests are correctly proxied to the Immich server:
|
||||
|
||||
```nginx
|
||||
location = /.well-known/immich {
|
||||
proxy_pass http://<backend_url>:2283;
|
||||
}
|
||||
```
|
||||
|
||||
By doing so, you'll maintain the functionality of Let's Encrypt while allowing mobile clients to access the necessary Immich path without obstruction.
|
||||
|
||||
### Caddy example config
|
||||
|
||||
As an alternative to nginx, you can also use [Caddy](https://caddyserver.com/) as a reverse proxy (with automatic HTTPS configuration). Below is an example config.
|
||||
|
||||
@@ -7,7 +7,7 @@ If a storage quota has been defined for the user, the usage number will be displ
|
||||
:::
|
||||
|
||||
:::info External library
|
||||
External library is not included in the storage quota.
|
||||
External libraries are not included in the storage quota.
|
||||
:::
|
||||
|
||||
<img src={require('./img/server-stats.png').default} title="server statistic" />
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
## Folder checks
|
||||
|
||||
:::info
|
||||
The folders considered for these checks include: `upload/`, `library/`, `thumbs/`, `encoded-video/`, `profile/`
|
||||
The folders considered for these checks include: `upload/`, `library/`, `thumbs/`, `encoded-video/`, `profile/`, `backups/`
|
||||
:::
|
||||
|
||||
When Immich starts, it performs a series of checks in order to validate that it can read and write files to the volume mounts used by the storage system. If it cannot perform all the required operations, it will fail to start. The checks include:
|
||||
@@ -40,7 +40,9 @@ The above error messages show that the server has previously (successfully) writ
|
||||
|
||||
### Ignoring the checks
|
||||
|
||||
The checks are designed to catch common problems that we have seen users have in the past, but if you want to disable them you can set the following environment variable:
|
||||
:::warning
|
||||
The checks are designed to catch common problems that we have seen users have in the past, and often indicate there's something wrong that you should solve. If you know what you're doing and you want to disable them you can set the following environment variable:
|
||||
:::
|
||||
|
||||
```
|
||||
IMMICH_IGNORE_MOUNT_CHECK_ERRORS=true
|
||||
|
||||
@@ -15,7 +15,7 @@ Our [GitHub Repository](https://github.com/immich-app/immich) is a [monorepo](ht
|
||||
| `design/` | Screenshots and logos for the README |
|
||||
| `docs/` | Source code for the [https://immich.app](https://immich.app) website |
|
||||
| `machine-learning/` | Source code for the `immich-machine-learning` docker image |
|
||||
| `misc/release/` | Scripts for version pumps and draft releases |
|
||||
| `misc/release/` | Scripts for version bumps and draft releases |
|
||||
| `mobile/` | Source code for the mobile app, both Android and iOS |
|
||||
| `server/` | Source code for the `immich-server` docker image |
|
||||
| `web/` | Source code for the `web` |
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# PR Checklist
|
||||
|
||||
A minimal devcontainer is supplied with this repository. All commands can be executed directly inside this container to avoid tedious installation of the environment.
|
||||
:::warning
|
||||
The provided devcontainer isn't complete at the moment. At least all dockerized steps in the Makefile won't work (`make dev`, ....). Feel free to contribute!
|
||||
:::
|
||||
When contributing code through a pull request, please check the following:
|
||||
|
||||
## Web Checks
|
||||
|
||||
@@ -76,7 +76,7 @@ Setting these in the IDE give a better developer experience, auto-formatting cod
|
||||
|
||||
### Dart Code Metrics
|
||||
|
||||
The mobile app uses DCM (Dart Code Metrics) for linting and metrics calculation. Please refer to the [Getting Started](https://dcm.dev/docs/getting-started/#installation) page for more information on setting up DCM
|
||||
The mobile app uses DCM (Dart Code Metrics) for linting and metrics calculation. Please refer to the [Getting Started](https://dcm.dev/docs/) page for more information on setting up DCM
|
||||
|
||||
Note: Activating the license is not required.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Hardware Transcoding [Experimental]
|
||||
|
||||
This feature allows you to use a GPU to accelerate transcoding and reduce CPU load.
|
||||
Note that hardware transcoding is much less efficient for file sizes.
|
||||
Note that hardware transcoding produces significantly larger videos than software transcoding with similar settings, typically with lower quality. Using slow presets and preferring more efficient codecs can narrow this gap.
|
||||
As this is a new feature, it is still experimental and may not work on all systems.
|
||||
|
||||
:::info
|
||||
@@ -23,7 +23,7 @@ You do not need to redo any transcoding jobs after enabling hardware acceleratio
|
||||
- Raspberry Pi is currently not supported.
|
||||
- Two-pass mode is only supported for NVENC. Other APIs will ignore this setting.
|
||||
- By default, only encoding is currently hardware accelerated. This means the CPU is still used for software decoding and tone-mapping.
|
||||
- NVENC and RKMPP can be fully accelerated by enabling hardware decoding in the video transcoding settings.
|
||||
- You can benefit from end-to-end acceleration by enabling hardware decoding in the video transcoding settings.
|
||||
- Hardware dependent
|
||||
- Codec support varies, but H.264 and HEVC are usually supported.
|
||||
- Notably, NVIDIA and AMD GPUs do not support VP9 encoding.
|
||||
@@ -62,11 +62,14 @@ For RKMPP to work:
|
||||
1. If you do not already have it, download the latest [`hwaccel.transcoding.yml`][hw-file] file and ensure it's in the same folder as the `docker-compose.yml`.
|
||||
2. In the `docker-compose.yml` under `immich-server`, uncomment the `extends` section and change `cpu` to the appropriate backend.
|
||||
|
||||
- For VAAPI on WSL2, be sure to use `vaapi-wsl` rather than `vaapi`
|
||||
Note: For VAAPI on WSL2, be sure to use `vaapi-wsl` rather than `vaapi`
|
||||
|
||||
3. Redeploy the `immich-server` container with these updated settings.
|
||||
4. In the Admin page under `Video transcoding settings`, change the hardware acceleration setting to the appropriate option and save.
|
||||
5. (Optional) If using a compatible backend, you may enable hardware decoding for optimal performance.
|
||||
|
||||
Note: For Jasper Lake and Elkhart Lake CPUs, you will need to set the `Hardware Acceleration` -> `Constant quality mode` to `CQP`
|
||||
|
||||
5. (Optional) Enable hardware decoding for optimal performance.
|
||||
|
||||
#### Single Compose File
|
||||
|
||||
|
||||
BIN
docs/docs/features/img/folder-view.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
docs/docs/features/img/mobile-upload-open-photo.png
Normal file
|
After Width: | Height: | Size: 379 KiB |
BIN
docs/docs/features/img/mobile-upload-selected-photos.png
Normal file
|
After Width: | Height: | Size: 2.1 MiB |
@@ -149,6 +149,22 @@ If you get an error here, please rename the other external library to something
|
||||
|
||||
Within seconds, the assets from the old-pics and videos folders should show up in the main timeline.
|
||||
|
||||
### Folder view
|
||||
|
||||
:::info
|
||||
This feature also exists for assets uploaded other than through external libraries.
|
||||
:::tip
|
||||
You can use the storage template migration feature for the best experience with uploaded assets in this view.
|
||||
:::
|
||||
|
||||
You can browse your photos and videos by folder like in a file explorer.
|
||||
|
||||
Enable this feature from the Users Settings > Features > Folders.
|
||||
|
||||
The UI is currently only available for the web; mobile will come in a subsequent release.
|
||||
|
||||
<img src={require('./img/folder-view.png').default} width="75%" title='Folder-view' />
|
||||
|
||||
### Set Custom Scan Interval
|
||||
|
||||
:::note
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import Icon from '@mdi/react';
|
||||
import { mdiCloudOffOutline, mdiCloudCheckOutline } from '@mdi/js';
|
||||
import MobileAppDownload from '/docs/partials/_mobile-app-download.md';
|
||||
import MobileAppLogin from '/docs/partials/_mobile-app-login.md';
|
||||
import MobileAppBackup from '/docs/partials/_mobile-app-backup.md';
|
||||
import { cloudDonePath, cloudOffPath } from '@site/src/components/svg-paths';
|
||||
|
||||
# Mobile App
|
||||
|
||||
@@ -27,3 +30,63 @@ The beta release channel allows users to test upcoming changes before they are o
|
||||
:::info
|
||||
You can enable automatic backup on supported devices. For more information see [Automatic Backup](/docs/features/automatic-backup.md).
|
||||
:::
|
||||
|
||||
## Sync only selected photos
|
||||
|
||||
If you have a large number of photos on the device, and you would prefer not to backup all the photos, then it might be prudent to only backup selected photos from device to the Immich server.
|
||||
|
||||
First, you need to enable the Storage Indicator in your app's settings. Navigate to **<ins>Settings -> Photo Grid</ins>** and enable **"Show Storage indicator on asset tiles"**; this makes it easy to distinguish local-only assets and synced assets.
|
||||
:::note
|
||||
This will enable a small cloud icon on the bottom right corner of the asset tile, indicating that the asset is synced to the server:
|
||||
|
||||
1. <Icon path={mdiCloudOffOutline} size={1} /> - Local-only asset; not synced to the server
|
||||
2. <Icon path={mdiCloudCheckOutline} size={1} /> - Asset is synced to the server :::
|
||||
|
||||
Now make sure that the local album is selected in the backup screen (steps 1-2 above). You can find these albums listed in **<ins>Library -> On this device</ins>**. To selectively upload photos from these albums, simply select the local-only photos and tap on "Upload" button in the dynamic bottom menu.
|
||||
|
||||
<img
|
||||
src={require('./img/mobile-upload-open-photo.png').default}
|
||||
width="50%"
|
||||
title="Upload button on local asset preview"
|
||||
/>
|
||||
<img
|
||||
src={require('./img/mobile-upload-selected-photos.png').default}
|
||||
width="40%"
|
||||
title="Upload button after photos selection"
|
||||
/>
|
||||
|
||||
## Album Sync
|
||||
|
||||
You can sync or mirror an album from your phone to the Immich server on your account. For example, if you select Recents, Camera and Videos album for backup, the corresponding album with the same name will be created on the server. Once the assets from those albums are uploaded, they will be put into the target albums automatically.
|
||||
|
||||
### Album Synchronization Highlights
|
||||
|
||||
- **One-Way Sync:** Synchronization is one-way, from the device to the server.
|
||||
|
||||
- **Name Matching:** If an album on the server has the same name as the album on the device, images from the device will be merged with the existing images in the server album.
|
||||
|
||||
- **Shared Albums:** If the matching album on the server is shared, the new photos merged into the album will also be shared.
|
||||
|
||||
- **Album Structure:** When an album is created for the first time, its structure is based on the initial state. Future updates made on the phone (such as deleting or repositioning photos) will not be reflected in Immich.
|
||||
|
||||
- **User-Specific Sync:** Album synchronization is unique to each server user and does not sync between different users or partners.
|
||||
|
||||
- **Mobile-Only Feature:** Album synchronization is currently only available on mobile. For similar options on a computer, refer to [Libraries](/docs/features/libraries) for further details.
|
||||
|
||||
### Synchronizing albums from the past
|
||||
|
||||
Albums can be synchronized to the server even if they did not exist on the server before. In order to apply this setting you have to:
|
||||
Enter the cloud on the top right -> cog wheel on the top right -> select the sync option under Sync albums.
|
||||
|
||||
:::info Sync albums delete/move photos
|
||||
If you delete/move photos in the local album on your device, it will not be reflected in the album on the server **even if** you click Sync albums
|
||||
It will only reflect files you add.
|
||||
:::
|
||||
|
||||
If the same asset is in more than one album it will only sync to the first album it's in, after that it won't sync again even if the user clicks sync albums manually.
|
||||
To overcome this limitation, the files must be removed from the blacklist by
|
||||
App settings -> Advanced -> Duplicate Assets -> Clear
|
||||
|
||||
:::info
|
||||
Cleaning duplicate assets from the list will cause all the previously uploaded duplicate files to be re-uploaded, the files will not actually be uploaded and will be rejected on the server side (due to duplication) but will be synchronized to the album and at the end will be added to the black list again at the end of the synchronization.
|
||||
:::
|
||||
|
||||
@@ -25,10 +25,10 @@ The metrics in immich are grouped into API (endpoint calls and response times),
|
||||
|
||||
### Configuration
|
||||
|
||||
Immich will not expose an endpoint for metrics by default. To enable this endpoint, you can add the `IMMICH_METRICS=true` environmental variable to your `.env` file. Note that only the server and microservices containers currently use this variable.
|
||||
Immich will not expose an endpoint for metrics by default. To enable this endpoint, you can add the `IMMICH_TELEMETRY_INCLUDE=all` environmental variable to your `.env` file. Note that only the server container currently use this variable.
|
||||
|
||||
:::tip
|
||||
`IMMICH_METRICS` enables all metrics, but there are also [environmental variables](/docs/install/environment-variables.md#prometheus) to toggle specific metric groups. If you'd like to only expose certain kinds of metrics, you can set only those environmental variables to `true`. Explicitly setting the environmental variable for a metric group overrides `IMMICH_METRICS` for that group. For example, setting `IMMICH_METRICS=true` and `IMMICH_API_METRICS=false` will enable all metrics except API metrics.
|
||||
`IMMICH_TELEMETRY_INCLUDE=all` enables all metrics. For a more granular configuration you can enumerate the telemetry metrics that should be included as a comma separated list (e.g. `IMMICH_TELEMETRY_INCLUDE=repo,api`). Alternatively, you can also exclude specific metrics with `IMMICH_TELEMETRY_EXCLUDE`. For more information refer to the [environment section](/docs/install/environment-variables.md#prometheus).
|
||||
:::
|
||||
|
||||
The next step is to configure a new or existing Prometheus instance to scrape this endpoint. The following steps assume that you do not have an existing Prometheus instance, but the steps will be similar either way.
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
# Files Custom Locations
|
||||
|
||||
This guide explains storing generated and raw files with docker's volume mount in different locations.
|
||||
This guide explains how to store generated and raw files with docker's volume mount in different locations.
|
||||
|
||||
:::caution Backup
|
||||
It is important to remember to update the backup settings after following the guide to back up the new backup paths if using automatic backup tools, especially `profile/`.
|
||||
:::
|
||||
|
||||
In our `.env` file, we will define variables that will help us in the future when we want to move to a more advanced server in the future
|
||||
In our `.env` file, we will define variables that will help us in the future when we want to move to a more advanced server
|
||||
|
||||
```diff title=".env"
|
||||
# You can find documentation for all the supported env variables [here](/docs/install/environment-variables)
|
||||
# You can find documentation for all the supported environment variables [here](/docs/install/environment-variables)
|
||||
|
||||
# Custom location where your uploaded, thumbnails, and transcoded video files are stored
|
||||
- UPLOAD_LOCATION=./library
|
||||
@@ -17,10 +17,11 @@ In our `.env` file, we will define variables that will help us in the future whe
|
||||
+ THUMB_LOCATION=/custom/path/immich/thumbs
|
||||
+ ENCODED_VIDEO_LOCATION=/custom/path/immich/encoded-video
|
||||
+ PROFILE_LOCATION=/custom/path/immich/profile
|
||||
+ BACKUP_LOCATION=/custom/path/immich/backups
|
||||
...
|
||||
```
|
||||
|
||||
After defining the locations for these files, we will edit the `docker-compose.yml` file accordingly and add the new variables to the `immich-server` container.
|
||||
After defining the locations of these files, we will edit the `docker-compose.yml` file accordingly and add the new variables to the `immich-server` container.
|
||||
|
||||
```diff title="docker-compose.yml"
|
||||
services:
|
||||
@@ -30,6 +31,7 @@ services:
|
||||
+ - ${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
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
```
|
||||
|
||||
@@ -41,12 +43,11 @@ 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 network storage to `/usr/src/app/upload` and then mount the folders we want quick access to below this folder.
|
||||
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.
|
||||
|
||||
The `thumbs/` folder contains both the small thumbnails shown in the timeline, and the larger previews shown when clicking into an image. These cannot be split up.
|
||||
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.
|
||||
|
||||
The storage metrics of the Immich server will track the storage available at `UPLOAD_LOCATION`,
|
||||
so the administrator should setup some kind of monitoring to make sure the SSD does not run out of space. The `profile/` folder is much smaller, typically less than 1 MB.
|
||||
The storage metrics of the Immich server will track available storage at `UPLOAD_LOCATION`, so the administrator must set up some sort of monitoring to ensure the storage does not run out of space. The `profile/` folder is much smaller, usually less than 1 MB.
|
||||
:::
|
||||
|
||||
Thanks to [Jrasm91](https://github.com/immich-app/immich/discussions/2110#discussioncomment-5477767) for writing the guide.
|
||||
|
||||
@@ -98,6 +98,10 @@ SELECT * FROM "move_history";
|
||||
SELECT * FROM "users";
|
||||
```
|
||||
|
||||
```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';
|
||||
```
|
||||
|
||||
## System Config
|
||||
|
||||
```sql title="Custom settings"
|
||||
|
||||
@@ -6,6 +6,15 @@ This script assumes you have a second hard drive connected to your server for on
|
||||
|
||||
The database is saved to your Immich upload folder in the `database-backup` subdirectory. The database is then backed up and versioned with your assets by Borg. This ensures that the database backup is in sync with your assets in every snapshot.
|
||||
|
||||
:::info
|
||||
This script makes backups of your database along with your photo/video library. This is redundant with the [automatic database backup tool](https://immich.app/docs/administration/backup-and-restore#automatic-database-backups) built into Immich. Using this script to backup your database has two advantages over the built-in backup tool:
|
||||
|
||||
- This script uses storage more efficiently by versioning your backups instead of making multiple copies.
|
||||
- The database backups are performed at the same time as the library backup, ensuring that the backups of your database and the library are always in sync.
|
||||
|
||||
If you are using this script, it is therefore safe to turn off the built-in automatic database backups from your admin panel to save storage space.
|
||||
:::
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Borg needs to be installed on your server as well as the remote machine. You can find instructions to install Borg [here](https://borgbackup.readthedocs.io/en/latest/installation.html).
|
||||
|
||||
@@ -19,14 +19,13 @@ The default configuration looks like this:
|
||||
"targetVideoCodec": "h264",
|
||||
"acceptedVideoCodecs": ["h264"],
|
||||
"targetAudioCodec": "aac",
|
||||
"acceptedAudioCodecs": ["aac", "mp3", "libopus"],
|
||||
"acceptedAudioCodecs": ["aac", "mp3", "libopus", "pcm_s16le"],
|
||||
"acceptedContainers": ["mov", "ogg", "webm"],
|
||||
"targetResolution": "720",
|
||||
"maxBitrate": "0",
|
||||
"bframes": -1,
|
||||
"refs": 0,
|
||||
"gopSize": 0,
|
||||
"npl": 0,
|
||||
"temporalAQ": false,
|
||||
"cqMode": "auto",
|
||||
"twoPass": false,
|
||||
@@ -36,6 +35,13 @@ The default configuration looks like this:
|
||||
"accel": "disabled",
|
||||
"accelDecode": false
|
||||
},
|
||||
"backup": {
|
||||
"database": {
|
||||
"enabled": true,
|
||||
"cronExpression": "0 02 * * *",
|
||||
"keepLastAmount": 14
|
||||
}
|
||||
},
|
||||
"job": {
|
||||
"backgroundTask": {
|
||||
"concurrency": 5
|
||||
|
||||
@@ -148,23 +148,24 @@ Redis (Sentinel) URL example JSON before encoding:
|
||||
|
||||
## Machine Learning
|
||||
|
||||
| Variable | Description | Default | Containers |
|
||||
| :-------------------------------------------------------- | :-------------------------------------------------------------------------------------------------- | :-----------------------------------: | :--------------- |
|
||||
| `MACHINE_LEARNING_MODEL_TTL` | Inactivity time (s) before a model is unloaded (disabled if \<= 0) | `300` | machine learning |
|
||||
| `MACHINE_LEARNING_MODEL_TTL_POLL_S` | Interval (s) between checks for the model TTL (disabled if \<= 0) | `10` | machine learning |
|
||||
| `MACHINE_LEARNING_CACHE_FOLDER` | Directory where models are downloaded | `/cache` | machine learning |
|
||||
| `MACHINE_LEARNING_REQUEST_THREADS`<sup>\*1</sup> | Thread count of the request thread pool (disabled if \<= 0) | number of CPU cores | machine learning |
|
||||
| `MACHINE_LEARNING_MODEL_INTER_OP_THREADS` | Number of parallel model operations | `1` | machine learning |
|
||||
| `MACHINE_LEARNING_MODEL_INTRA_OP_THREADS` | Number of threads for each model operation | `2` | machine learning |
|
||||
| `MACHINE_LEARNING_WORKERS`<sup>\*2</sup> | Number of worker processes to spawn | `1` | machine learning |
|
||||
| `MACHINE_LEARNING_HTTP_KEEPALIVE_TIMEOUT_S`<sup>\*3</sup> | HTTP Keep-alive time in seconds | `2` | machine learning |
|
||||
| `MACHINE_LEARNING_WORKER_TIMEOUT` | Maximum time (s) of unresponsiveness before a worker is killed | `120` (`300` if using OpenVINO image) | machine learning |
|
||||
| `MACHINE_LEARNING_PRELOAD__CLIP` | Name of a CLIP model to be preloaded and kept in cache | | machine learning |
|
||||
| `MACHINE_LEARNING_PRELOAD__FACIAL_RECOGNITION` | Name of a facial recognition model to be preloaded and kept in cache | | machine learning |
|
||||
| `MACHINE_LEARNING_ANN` | Enable ARM-NN hardware acceleration if supported | `True` | machine learning |
|
||||
| `MACHINE_LEARNING_ANN_FP16_TURBO` | Execute operations in FP16 precision: increasing speed, reducing precision (applies only to ARM-NN) | `False` | machine learning |
|
||||
| `MACHINE_LEARNING_ANN_TUNING_LEVEL` | ARM-NN GPU tuning level (1: rapid, 2: normal, 3: exhaustive) | `2` | machine learning |
|
||||
| `MACHINE_LEARNING_DEVICE_IDS`<sup>\*4</sup> | Device IDs to use in multi-GPU environments | `0` | machine learning |
|
||||
| Variable | Description | Default | Containers |
|
||||
| :-------------------------------------------------------- | :-------------------------------------------------------------------------------------------------- | :-----------------------------: | :--------------- |
|
||||
| `MACHINE_LEARNING_MODEL_TTL` | Inactivity time (s) before a model is unloaded (disabled if \<= 0) | `300` | machine learning |
|
||||
| `MACHINE_LEARNING_MODEL_TTL_POLL_S` | Interval (s) between checks for the model TTL (disabled if \<= 0) | `10` | machine learning |
|
||||
| `MACHINE_LEARNING_CACHE_FOLDER` | Directory where models are downloaded | `/cache` | machine learning |
|
||||
| `MACHINE_LEARNING_REQUEST_THREADS`<sup>\*1</sup> | Thread count of the request thread pool (disabled if \<= 0) | number of CPU cores | machine learning |
|
||||
| `MACHINE_LEARNING_MODEL_INTER_OP_THREADS` | Number of parallel model operations | `1` | machine learning |
|
||||
| `MACHINE_LEARNING_MODEL_INTRA_OP_THREADS` | Number of threads for each model operation | `2` | machine learning |
|
||||
| `MACHINE_LEARNING_WORKERS`<sup>\*2</sup> | Number of worker processes to spawn | `1` | machine learning |
|
||||
| `MACHINE_LEARNING_HTTP_KEEPALIVE_TIMEOUT_S`<sup>\*3</sup> | HTTP Keep-alive time in seconds | `2` | machine learning |
|
||||
| `MACHINE_LEARNING_WORKER_TIMEOUT` | Maximum time (s) of unresponsiveness before a worker is killed | `120` (`300` if using OpenVINO) | machine learning |
|
||||
| `MACHINE_LEARNING_PRELOAD__CLIP` | Name of a CLIP model to be preloaded and kept in cache | | machine learning |
|
||||
| `MACHINE_LEARNING_PRELOAD__FACIAL_RECOGNITION` | Name of a facial recognition model to be preloaded and kept in cache | | machine learning |
|
||||
| `MACHINE_LEARNING_ANN` | Enable ARM-NN hardware acceleration if supported | `True` | machine learning |
|
||||
| `MACHINE_LEARNING_ANN_FP16_TURBO` | Execute operations in FP16 precision: increasing speed, reducing precision (applies only to ARM-NN) | `False` | machine learning |
|
||||
| `MACHINE_LEARNING_ANN_TUNING_LEVEL` | ARM-NN GPU tuning level (1: rapid, 2: normal, 3: exhaustive) | `2` | machine learning |
|
||||
| `MACHINE_LEARNING_DEVICE_IDS`<sup>\*4</sup> | Device IDs to use in multi-GPU environments | `0` | machine learning |
|
||||
| `MACHINE_LEARNING_MAX_BATCH_SIZE__FACIAL_RECOGNITION` | Set the maximum number of faces that will be processed at once by the facial recognition model | None (`1` if using OpenVINO) | machine learning |
|
||||
|
||||
\*1: It is recommended to begin with this parameter when changing the concurrency levels of the machine learning service and then tune the other ones.
|
||||
|
||||
@@ -182,15 +183,10 @@ Other machine learning parameters can be tuned from the admin UI.
|
||||
|
||||
## Prometheus
|
||||
|
||||
| Variable | Description | Default | Containers | Workers |
|
||||
| :----------------------------- | :-------------------------------------------------------------------------------------------- | :-----: | :--------- | :----------------- |
|
||||
| `IMMICH_METRICS`<sup>\*1</sup> | Toggle all metrics (one of [`true`, `false`]) | | server | api, microservices |
|
||||
| `IMMICH_API_METRICS` | Toggle metrics for endpoints and response times (one of [`true`, `false`]) | | server | api, microservices |
|
||||
| `IMMICH_HOST_METRICS` | Toggle metrics for CPU and memory utilization for host and process (one of [`true`, `false`]) | | server | api, microservices |
|
||||
| `IMMICH_IO_METRICS` | Toggle metrics for database queries, image processing, etc. (one of [`true`, `false`]) | | server | api, microservices |
|
||||
| `IMMICH_JOB_METRICS` | Toggle metrics for jobs and queues (one of [`true`, `false`]) | | server | api, microservices |
|
||||
|
||||
\*1: Overridden for a metric group when its corresponding environmental variable is set.
|
||||
| Variable | Description | Default | Containers | Workers |
|
||||
| :------------------------- | :-------------------------------------------------------------------------------------------------------------------- | :-----: | :--------- | :----------------- |
|
||||
| `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
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 127 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 128 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 12 KiB |
BIN
docs/docs/install/img/truenas10.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
docs/docs/install/img/truenas11.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
docs/docs/install/img/truenas12.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
@@ -8,7 +8,7 @@ Hardware and software requirements for Immich:
|
||||
|
||||
## Software
|
||||
|
||||
- [Docker](https://docs.docker.com/get-docker/)
|
||||
- [Docker](https://docs.docker.com/engine/install/)
|
||||
- [Docker Compose](https://docs.docker.com/compose/install/)
|
||||
|
||||
:::note
|
||||
|
||||
@@ -7,7 +7,9 @@ sidebar_position: 80
|
||||
:::note
|
||||
This is a community contribution and not officially supported by the Immich team, but included here for convenience.
|
||||
|
||||
**Please report issues to the corresponding [Github Repository](https://github.com/truenas/charts/tree/master/community/immich).**
|
||||
Community support can be found in the dedicated channel on the [Discord Server](https://discord.immich.app/).
|
||||
|
||||
**Please report app issues to the corresponding [Github Repository](https://github.com/truenas/charts/tree/master/community/immich).**
|
||||
:::
|
||||
|
||||
Immich can easily be installed on TrueNAS SCALE via the **Community** train application.
|
||||
@@ -20,18 +22,26 @@ TrueNAS SCALE makes installing and updating Immich easy, but you must use the Im
|
||||
The Immich app in TrueNAS SCALE installs, completes the initial configuration, then starts the Immich web portal.
|
||||
When updates become available, SCALE alerts and provides easy updates.
|
||||
|
||||
Before installing the Immich app in SCALE, review the [Environment Variables](/docs/install/environment-variables.md) documentation to see if you want to configure any during installation.
|
||||
You can configure environment variables at any time after deploying the application.
|
||||
Before installing the Immich app in SCALE, review the [Environment Variables](#environment-variables) documentation to see if you want to configure any during installation.
|
||||
You may also configure environment variables at any time after deploying the application.
|
||||
|
||||
You can allow SCALE to create the datasets Immich requires automatically during app installation.
|
||||
Or before beginning app installation, [create the datasets](https://www.truenas.com/docs/scale/scaletutorials/storage/datasets/datasetsscale/) to use in the **Storage Configuration** section during installation.
|
||||
Immich requires seven datasets: **library**, **pgBackup**, **pgData**, **profile**, **thumbs**, **uploads**, and **video**.
|
||||
You can organize these as one parent with seven child datasets, for example `mnt/tank/immich/library`, `mnt/tank/immich/pgBackup`, and so on.
|
||||
### Setting up Storage Datasets
|
||||
|
||||
Before beginning app installation, [create the datasets](https://www.truenas.com/docs/scale/scaletutorials/storage/datasets/datasetsscale/) to use in the **Storage Configuration** section during installation.
|
||||
Immich requires seven datasets: `library`, `upload`, `thumbs`, `profile`, `video`, `backups`, and `pgData`.
|
||||
You can organize these as one parent with seven child datasets, for example `/mnt/tank/immich/library`, `/mnt/tank/immich/upload`, and so on.
|
||||
|
||||
<img
|
||||
src={require('./img/truenas12.png').default}
|
||||
width="30%"
|
||||
alt="Immich App Widget"
|
||||
className="border rounded-xl"
|
||||
/>
|
||||
|
||||
:::info Permissions
|
||||
The **pgData** dataset must be owned by the user `netdata` (UID 999) for postgres to start. The other datasets must be owned by the user `root` (UID 0) or a group that includes the user `root` (UID 0) for immich to have the necessary permissions.
|
||||
|
||||
The **library** dataset must have [ACL mode](https://www.truenas.com/docs/core/coretutorials/storage/pools/permissions/#access-control-lists) set to `Passthrough` if you plan on using a [storage template](/docs/administration/storage-template.mdx) and the dataset is configured for network sharing (its ACL type is set to `SMB/NFSv4`). When the template is applied and files need to be moved from **uploads** to **library**, immich performs `chmod` internally and needs to be allowed to execute the command.
|
||||
If the **library** dataset uses ACL it must have [ACL mode](https://www.truenas.com/docs/core/coretutorials/storage/pools/permissions/#access-control-lists) set to `Passthrough` if you plan on using a [storage template](/docs/administration/storage-template.mdx) and the dataset is configured for network sharing (its ACL type is set to `SMB/NFSv4`). When the template is applied and files need to be moved from **upload** to **library**, immich performs `chmod` internally and needs to be allowed to execute the command. [More info.](https://github.com/immich-app/immich/pull/13017)
|
||||
:::
|
||||
|
||||
## Installing the Immich Application
|
||||
@@ -47,6 +57,8 @@ className="border rounded-xl"
|
||||
|
||||
Click on the widget to open the **Immich** application details screen.
|
||||
|
||||
<br/><br/>
|
||||
|
||||
<img
|
||||
src={require('./img/truenas02.png').default}
|
||||
width="100%"
|
||||
@@ -56,9 +68,13 @@ className="border rounded-xl"
|
||||
|
||||
Click **Install** to open the Immich application configuration screen.
|
||||
|
||||
<br/><br/>
|
||||
|
||||
Application configuration settings are presented in several sections, each explained below.
|
||||
To find specific fields click in the **Search Input Fields** search field, scroll down to a particular section or click on the section heading on the navigation area in the upper-right corner.
|
||||
|
||||
### Application Name and Version
|
||||
|
||||
<img
|
||||
src={require('./img/truenas03.png').default}
|
||||
width="100%"
|
||||
@@ -66,21 +82,123 @@ alt="Install Immich Screen"
|
||||
className="border rounded-xl"
|
||||
/>
|
||||
|
||||
Accept the default values in **Application Name** and **Version**.
|
||||
Accept the default value or enter a name in **Application Name** field.
|
||||
In most cases use the default name, but if adding a second deployment of the application you must change this name.
|
||||
|
||||
Accept the default version number in **Version**.
|
||||
When a new version becomes available, the application has an update badge.
|
||||
The **Installed Applications** screen shows the option to update applications.
|
||||
|
||||
### Immich Configuration
|
||||
|
||||
<img
|
||||
src={require('./img/truenas05.png').default}
|
||||
width="40%"
|
||||
alt="Configuration Settings"
|
||||
className="border rounded-xl"
|
||||
/>
|
||||
|
||||
Accept the default value in **Timezone** or change to match your local timezone.
|
||||
**Timezone** is only used by the Immich `exiftool` microservice if it cannot be determined from the image metadata.
|
||||
|
||||
Accept the default port in **Web Port**.
|
||||
Untick **Enable Machine Learning** if you will not use face recognition, image search, and smart duplicate detection.
|
||||
|
||||
Accept the default option or select the **Machine Learning Image Type** for your hardware based on the [Hardware-Accelerated Machine Learning Supported Backends](/docs/features/ml-hardware-acceleration.md#supported-backends).
|
||||
|
||||
Immich's default is `postgres` but you should consider setting the **Database Password** to a custom value using only the characters `A-Za-z0-9`.
|
||||
|
||||
The **Redis Password** should be set to a custom value using only the characters `A-Za-z0-9`.
|
||||
|
||||
Accept the **Log Level** default of **Log**.
|
||||
|
||||
Leave **Hugging Face Endpoint** blank. (This is for downloading ML models from a different source.)
|
||||
|
||||
Leave **Additional Environment Variables** blank or see [Environment Variables](#environment-variables) to set before installing.
|
||||
|
||||
### Network Configuration
|
||||
|
||||
<img
|
||||
src={require('./img/truenas06.png').default}
|
||||
width="40%"
|
||||
alt="Networking Settings"
|
||||
className="border rounded-xl"
|
||||
/>
|
||||
|
||||
Accept the default port `30041` in **WebUI Port** or enter a custom port number.
|
||||
:::info Allowed Port Numbers
|
||||
Only numbers within the range 9000-65535 may be used on SCALE versions below TrueNAS Scale 24.10 Electric Eel.
|
||||
|
||||
Regardless of version, to avoid port conflicts, don't use [ports on this list](https://www.truenas.com/docs/references/defaultports/).
|
||||
:::
|
||||
|
||||
### Storage Configuration
|
||||
|
||||
Immich requires seven storage datasets.
|
||||
You can allow SCALE to create them for you, or use the dataset(s) created in [First Steps](#first-steps).
|
||||
Select the storage options you want to use for **Immich Uploads Storage**, **Immich Library Storage**, **Immich Thumbs Storage**, **Immich Profile Storage**, **Immich Video Storage**, **Immich Postgres Data Storage**, **Immich Postgres Backup Storage**.
|
||||
Select **ixVolume (dataset created automatically by the system)** in **Type** to let SCALE create the dataset or select **Host Path** to use the existing datasets created on the system.
|
||||
|
||||
Accept the defaults in Resources or change the CPU and memory limits to suit your use case.
|
||||
<img
|
||||
src={require('./img/truenas07.png').default}
|
||||
width="20%"
|
||||
alt="Configure Storage ixVolumes"
|
||||
className="border rounded-xl"
|
||||
/>
|
||||
|
||||
Click **Install**.
|
||||
:::note Default Setting (Not recommended)
|
||||
The default setting for datasets is **ixVolume (dataset created automatically by the system)** but this results in your data being harder to access manually and can result in data loss if you delete the immich app. (Not recommended)
|
||||
:::
|
||||
|
||||
For each Storage option select **Host Path (Path that already exists on the system)** and then select the matching dataset [created before installing the app](#setting-up-storage-datasets): **Immich Library Storage**: `library`, **Immich Uploads Storage**: `upload`, **Immich Thumbs Storage**: `thumbs`, **Immich Profile Storage**: `profile`, **Immich Video Storage**: `video`, **Immich Backups Storage**: `backups`, **Postgres Data Storage**: `pgData`.
|
||||
|
||||
<img
|
||||
src={require('./img/truenas08.png').default}
|
||||
width="40%"
|
||||
alt="Configure Storage Host Paths"
|
||||
className="border rounded-xl"
|
||||
/>
|
||||
The image above has example values.
|
||||
|
||||
<br/>
|
||||
|
||||
### Additional Storage [(External Libraries)](/docs/features/libraries)
|
||||
|
||||
<img
|
||||
src={require('./img/truenas10.png').default}
|
||||
width="40%"
|
||||
alt="Configure Storage Host Paths"
|
||||
className="border rounded-xl"
|
||||
/>
|
||||
|
||||
You may configure [External Libraries](/docs/features/libraries) by mounting them using **Additional Storage**.
|
||||
The **Mount Path** is the loaction you will need to copy and paste into the External Library settings within Immich.
|
||||
The **Host Path** is the location on the TrueNAS SCALE server where your external library is located.
|
||||
|
||||
<!-- A section for Labels would go here but I don't know what they do. -->
|
||||
|
||||
### Resources Configuration
|
||||
|
||||
<img
|
||||
src={require('./img/truenas09.png').default}
|
||||
width="40%"
|
||||
alt="Resource Limits"
|
||||
className="border rounded-xl"
|
||||
/>
|
||||
|
||||
Accept the default **CPU** limit of `2` threads or specify the number of threads (CPUs with Multi-/Hyper-threading have 2 threads per core).
|
||||
|
||||
Accept the default **Memory** limit of `4096` MB or specify the number of MB of RAM. If you're using Machine Learning you should probably set this above 8000 MB.
|
||||
|
||||
:::info Older SCALE Versions
|
||||
Before TrueNAS SCALE version 24.10 Electric Eel:
|
||||
|
||||
The **CPU** value was specified in a different format with a default of `4000m` which is 4 threads.
|
||||
|
||||
The **Memory** value was specified in a different format with a default of `8Gi` which is 8 GiB of RAM. The value was specified in bytes or a number with a measurement suffix. Examples: `129M`, `123Mi`, `1000000000`
|
||||
:::
|
||||
|
||||
Enable **GPU Configuration** options if you have a GPU that you will use for [Hardware Transcoding](/docs/features/hardware-transcoding) and/or [Hardware-Accelerated Machine Learning](/docs/features/ml-hardware-acceleration.md). More info: [GPU Passtrough Docs for TrueNAS Apps](https://www.truenas.com/docs/truenasapps/#gpu-passthrough)
|
||||
|
||||
### Install
|
||||
|
||||
Finally, click **Install**.
|
||||
The system opens the **Installed Applications** screen with the Immich app in the **Deploying** state.
|
||||
When the installation completes it changes to **Running**.
|
||||
|
||||
@@ -97,102 +215,41 @@ Click **Web Portal** on the **Application Info** widget to open the Immich web i
|
||||
For more information on how to use the application once installed, please refer to the [Post Install](/docs/install/post-install.mdx) guide.
|
||||
:::
|
||||
|
||||
## Editing Environment Variables
|
||||
## Edit App Settings
|
||||
|
||||
Go to the **Installed Applications** screen and select Immich from the list of installed applications.
|
||||
Click **Edit** on the **Application Info** widget to open the **Edit Immich** screen.
|
||||
The settings on the edit screen are the same as on the install screen.
|
||||
You cannot edit **Storage Configuration** paths after the initial app install.
|
||||
- Go to the **Installed Applications** screen and select Immich from the list of installed applications.
|
||||
- Click **Edit** on the **Application Info** widget to open the **Edit Immich** screen.
|
||||
- Change any settings you would like to change.
|
||||
- The settings on the edit screen are the same as on the install screen.
|
||||
- Click **Update** at the very bottom of the page to save changes.
|
||||
- TrueNAS automatically updates, recreates, and redeploys the Immich container with the updated settings.
|
||||
|
||||
Click **Update** to save changes.
|
||||
TrueNAS automatically updates, recreates, and redeploys the Immich container with the updated environment variables.
|
||||
## Environment Variables
|
||||
|
||||
You can set [Environment Variables](/docs/install/environment-variables) by clicking **Add** on the **Additional Environment Variables** option and filling in the **Name** and **Value**.
|
||||
|
||||
<img
|
||||
src={require('./img/truenas11.png').default}
|
||||
width="40%"
|
||||
alt="Environment Variables"
|
||||
className="border rounded-xl"
|
||||
/>
|
||||
|
||||
:::info
|
||||
Some Environment Variables are not available for the TrueNAS SCALE app. This is mainly because they can be configured through GUI options in the [Edit Immich screen](#edit-app-settings).
|
||||
|
||||
Some examples are: `IMMICH_VERSION`, `UPLOAD_LOCATION`, `DB_DATA_LOCATION`, `TZ`, `IMMICH_LOG_LEVEL`, `DB_PASSWORD`, `REDIS_PASSWORD`.
|
||||
:::
|
||||
|
||||
## Updating the App
|
||||
|
||||
When updates become available, SCALE alerts and provides easy updates.
|
||||
To update the app to the latest version, click **Update** on the **Application Info** widget from the **Installed Applications** screen.
|
||||
To update the app to the latest version:
|
||||
|
||||
Update opens an update window for the application that includes two selectable options, Images (to be updated) and Changelog. Click on the down arrow to see the options available for each.
|
||||
|
||||
Click **Upgrade** to begin the process and open a counter dialog that shows the upgrade progress. When complete, the update badge and buttons disappear and the application Update state on the Installed screen changes from Update Available to Up to date.
|
||||
|
||||
## Understanding Immich Settings in TrueNAS SCALE
|
||||
|
||||
Accept the default value or enter a name in **Application Name** field.
|
||||
In most cases use the default name, but if adding a second deployment of the application you must change this name.
|
||||
|
||||
Accept the default version number in **Version**.
|
||||
When a new version becomes available, the application has an update badge.
|
||||
The **Installed Applications** screen shows the option to update applications.
|
||||
|
||||
### Immich Configuration Settings
|
||||
|
||||
You can accept the defaults in the **Immich Configuration** settings, or enter the settings you want to use.
|
||||
|
||||
<img
|
||||
src={require('./img/truenas05.png').default}
|
||||
width="100%"
|
||||
alt="Configuration Settings"
|
||||
className="border rounded-xl"
|
||||
/>
|
||||
|
||||
Accept the default setting in **Timezone** or change to match your local timezone.
|
||||
**Timezone** is only used by the Immich `exiftool` microservice if it cannot be determined from the image metadata.
|
||||
|
||||
You can enter a **Public Login Message** to display on the login page, or leave it blank.
|
||||
|
||||
### Networking Settings
|
||||
|
||||
Accept the default port numbers in **Web Port**.
|
||||
The SCALE Immich app listens on port **30041**.
|
||||
|
||||
Refer to the TrueNAS [default port list](https://www.truenas.com/docs/references/defaultports/) for a list of assigned port numbers.
|
||||
To change the port numbers, enter a number within the range 9000-65535.
|
||||
|
||||
<img
|
||||
src={require('./img/truenas06.png').default}
|
||||
width="100%"
|
||||
alt="Networking Settings"
|
||||
className="border rounded-xl"
|
||||
/>
|
||||
|
||||
### Storage Settings
|
||||
|
||||
You can install Immich using the default setting **ixVolume (dataset created automatically by the system)** or use the host path option with datasets [created before installing the app](#first-steps).
|
||||
|
||||
<img
|
||||
src={require('./img/truenas07.png').default}
|
||||
width="100%"
|
||||
alt="Configure Storage ixVolumes"
|
||||
className="border rounded-xl"
|
||||
/>
|
||||
|
||||
Select **Host Path (Path that already exists on the system)** to browse to and select the datasets.
|
||||
|
||||
<img
|
||||
src={require('./img/truenas08.png').default}
|
||||
width="100%"
|
||||
alt="Configure Storage Host Paths"
|
||||
className="border rounded-xl"
|
||||
/>
|
||||
|
||||
### Resource Configuration Settings
|
||||
|
||||
Accept the default values in **Resources Configuration** or enter new CPU and memory values
|
||||
By default, this application is limited to use no more than 4 CPU cores and 8 Gigabytes available memory. The application might use considerably less system resources.
|
||||
|
||||
<img
|
||||
src={require('./img/truenas09.png').default}
|
||||
width="100%"
|
||||
alt="Resource Limits"
|
||||
className="border rounded-xl"
|
||||
/>
|
||||
|
||||
To customize the CPU and memory allocated to the container Immich uses, enter new CPU values as a plain integer value followed by the suffix m (milli).
|
||||
Default is 4000m.
|
||||
|
||||
Accept the default value 8Gi allocated memory or enter a new limit in bytes.
|
||||
Enter a plain integer followed by the measurement suffix, for example 129M or 123Mi.
|
||||
|
||||
Systems with compatible GPU(s) display devices in **GPU Configuration**.
|
||||
See [Managing GPUs](https://www.truenas.com/docs/scale/scaletutorials/systemsettings/advanced/managegpuscale/) for more information about allocating isolated GPU devices in TrueNAS SCALE.
|
||||
- Go to the **Installed Applications** screen and select Immich from the list of installed applications.
|
||||
- Click **Update** on the **Application Info** widget from the **Installed Applications** screen.
|
||||
- This opens an update window with some options
|
||||
- You may select an Image update too.
|
||||
- You may view the Changelog.
|
||||
- Click **Upgrade** to begin the process and open a counter dialog that shows the upgrade progress.
|
||||
- When complete, the update badge and buttons disappear and the application Update state on the Installed screen changes from Update Available to Up to date.
|
||||
|
||||
@@ -77,6 +77,7 @@ alt="Select Plugins > Compose.Manager > Add New Stack > Label it Immich"
|
||||
7. Paste the entire contents of the [Immich example.env](https://github.com/immich-app/immich/releases/latest/download/example.env) file into the Unraid editor, then **before saving** edit the following:
|
||||
|
||||
- `UPLOAD_LOCATION`: Create a folder in your Images Unraid share and place the **absolute** location here > For example my _"images"_ share has a folder within it called _"immich"_. If I browse to this directory in the terminal and type `pwd` the output is `/mnt/user/images/immich`. This is the exact value I need to enter as my `UPLOAD_LOCATION`
|
||||
- `DB_DATA_LOCATION`: Change this to use an Unraid share (preferably a cache pool, e.g. `/mnt/user/appdata`). If left at default it will try to use Unraid's `/boot/config/plugins/compose.manager/projects/[stack_name]/postgres` folder which it doesn't have permissions to, resulting in this container continuously restarting.
|
||||
|
||||
<img
|
||||
src={require('./img/unraid05.webp').default}
|
||||
|
||||
@@ -56,6 +56,7 @@ import MobileAppBackup from '/docs/partials/_mobile-app-backup.md';
|
||||
|
||||
The backup time differs depending on how many photos are on your mobile device. Large uploads may
|
||||
take quite a while.
|
||||
To quickly get going, you can selectively upload few photos first, by following this [guide](/docs/features/mobile-app#sync-only-selected-photos).
|
||||
|
||||
You can select the **Jobs** tab to see Immich processing your photos.
|
||||
|
||||
|
||||
@@ -16,5 +16,9 @@ Support the project by localizing on [Weblate](https://hosted.weblate.org/projec
|
||||
|
||||
If you are a programmer or developer, take a look at Immich's [technology stack](/docs/developer/architecture.mdx) and consider fixing bugs or building new features. The team and I are always looking for new contributors. For information about how to contribute as a developer, see the [Developer](/docs/developer/architecture.mdx) section.
|
||||
|
||||
## Purchase Immich
|
||||
|
||||
You can also [purchase Immich](https://buy.immich.app), for either one user or your entire server. Building Immich takes a lot of time and effort, and we have full-time engineers working on it to make it as good as we possibly can, so any support is greatly appreciated. Don't worry, all features will be free, forever! Nothing will ever be put behind any paywalls.
|
||||
|
||||
[github-issue]: https://github.com/immich-app/immich/issues/new/choose
|
||||
[github-langs]: https://github.com/immich-app/immich/tree/main/mobile/assets/i18n
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
Navigate to the backup screen by clicking on the cloud icon in the top right corner of the screen.
|
||||
1. Navigate to the backup screen by clicking on the cloud icon in the top right corner of the screen.
|
||||
|
||||
<img src={require('./img/backup-header.png').default} width='50%' title='Backup button' />
|
||||
|
||||
You can select which album(s) you want to back up to the Immich server from the backup screen.
|
||||
2. You can select which album(s) you want to back up to the Immich server from the backup screen.
|
||||
|
||||
<img src={require('./img/album-selection.png').default} width='50%' title='Backup button' />
|
||||
|
||||
Scroll down to the bottom and press "**Start Backup**" to start the backup process.
|
||||
3. Scroll down to the bottom and press "**Start Backup**" to start the backup process. This will upload all the assets in the selected albums.
|
||||
|
||||
@@ -31,5 +31,5 @@ Immich also provides a mechanism to migrate between templates so that if the tem
|
||||
If you want to store assets in album folders, but you also have assets that do not belong to any album, you can use `{{#if album}}`, `{{else}}` and `{{/if}}` to create a conditional statement. For example, the following template will store assets in album folders if they belong to an album, and in a folder named "Other/Month" if they do not belong to an album:
|
||||
|
||||
```
|
||||
{{y}}/{{#if album}}{{album}}{{else}}Other/{{MM}}{{/if}}/{{filename}}
|
||||
{{y}}/{{#if album}}{{album}}{{else}}Other{{/if}}/{{MM}}/{{filename}}
|
||||
```
|
||||
|
||||
19
docs/package-lock.json
generated
@@ -3006,9 +3006,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mdx-js/react": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.0.1.tgz",
|
||||
"integrity": "sha512-9ZrPIU4MGf6et1m1ov3zKf+q9+deetI51zprKB1D/z3NOb+rUxxtEl3mCjW5wTGh6VhRdwPueh1oRzi6ezkA8A==",
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.0.tgz",
|
||||
"integrity": "sha512-QjHtSaoameoalGnKDT3FoIl4+9RwyTmo9ZJGBdLOks/YOiWHoRDI3PUwEzOE7kEmGcV3AFcp9K6dYu9rEuKLAQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/mdx": "^2.0.0"
|
||||
},
|
||||
@@ -16092,9 +16093,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tailwindcss": {
|
||||
"version": "3.4.13",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.13.tgz",
|
||||
"integrity": "sha512-KqjHOJKogOUt5Bs752ykCeiwvi0fKVkr5oqsFNt/8px/tA8scFPIlkygsf6jXrfCqGHz7VflA6+yytWuM+XhFw==",
|
||||
"version": "3.4.14",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.14.tgz",
|
||||
"integrity": "sha512-IcSvOcTRcUtQQ7ILQL5quRDg7Xs93PdJEk1ZLbhhvJc7uj/OAhYOnruEiwnGgBvUtaUAJ8/mhSw1o8L2jCiENA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@alloc/quick-lru": "^5.2.0",
|
||||
@@ -16454,9 +16455,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.6.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz",
|
||||
"integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==",
|
||||
"version": "5.6.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz",
|
||||
"integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==",
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
|
||||
@@ -56,6 +56,6 @@
|
||||
"node": ">=20"
|
||||
},
|
||||
"volta": {
|
||||
"node": "20.18.0"
|
||||
"node": "22.11.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,19 +35,24 @@ const guides: CommunityGuidesProps[] = [
|
||||
},
|
||||
{
|
||||
title: 'Google Photos import + albums',
|
||||
description: 'Import your Google Photos files into Immich and add your albums',
|
||||
description: 'Import your Google Photos files into Immich and add your albums.',
|
||||
url: 'https://github.com/immich-app/immich/discussions/1340',
|
||||
},
|
||||
{
|
||||
title: 'Access Immich with custom domain',
|
||||
description: 'Access your local Immich installation over the internet using your own domain',
|
||||
description: 'Access your local Immich installation over the internet using your own domain.',
|
||||
url: 'https://github.com/ppr88/immich-guides/blob/main/open-immich-custom-domain.md',
|
||||
},
|
||||
{
|
||||
title: 'Nginx caching map server',
|
||||
description: 'Increase privacy by using nginx as a caching proxy in front of a map tile server',
|
||||
description: 'Increase privacy by using nginx as a caching proxy in front of a map tile server.',
|
||||
url: 'https://github.com/pcouy/pcouy.github.io/blob/main/_posts/2024-08-30-proxying-a-map-tile-server-for-increased-privacy.md',
|
||||
},
|
||||
{
|
||||
title: 'fail2ban setup instructions',
|
||||
description: 'How to configure an existing fail2ban installation to block incorrect login attempts.',
|
||||
url: 'https://github.com/immich-app/immich/discussions/3243#discussioncomment-6681948',
|
||||
},
|
||||
];
|
||||
|
||||
function CommunityGuide({ title, description, url }: CommunityGuidesProps): JSX.Element {
|
||||
|
||||
@@ -83,6 +83,12 @@ const projects: CommunityProjectProps[] = [
|
||||
description: 'Power tools for organizing your immich library.',
|
||||
url: 'https://github.com/varun-raj/immich-power-tools',
|
||||
},
|
||||
{
|
||||
title: 'Immich Public Proxy',
|
||||
description:
|
||||
'Share your Immich photos and albums in a safe way without exposing your Immich instance to the public.',
|
||||
url: 'https://github.com/alangrainger/immich-public-proxy',
|
||||
},
|
||||
];
|
||||
|
||||
function CommunityProject({ title, description, url }: CommunityProjectProps): JSX.Element {
|
||||
|
||||
@@ -49,7 +49,7 @@ export function Timeline({ items }: Props): JSX.Element {
|
||||
<div className="flex flex-col flex-grow justify-between gap-2">
|
||||
<div className="flex gap-2 items-center">
|
||||
{cardIcon === 'immich' ? (
|
||||
<img src="img/immich-logo.svg" height="30" className="rounded-none" />
|
||||
<img src="/img/immich-logo.svg" height="30" className="rounded-none" />
|
||||
) : (
|
||||
<Icon path={cardIcon} size={1} color={item.iconColor} />
|
||||
)}
|
||||
|
||||
@@ -74,12 +74,14 @@ import {
|
||||
mdiFaceRecognition,
|
||||
mdiVideo,
|
||||
mdiWeb,
|
||||
mdiDatabaseOutline,
|
||||
} from '@mdi/js';
|
||||
import Layout from '@theme/Layout';
|
||||
import React from 'react';
|
||||
import { Item, Timeline } from '../components/timeline';
|
||||
|
||||
const releases = {
|
||||
'v1.120.0': new Date(2024, 10, 6),
|
||||
'v1.114.0': new Date(2024, 8, 6),
|
||||
'v1.113.0': new Date(2024, 7, 30),
|
||||
'v1.112.0': new Date(2024, 7, 14),
|
||||
@@ -151,6 +153,9 @@ const weirdTags = {
|
||||
'v1.2.0': 'v0.2-dev ',
|
||||
};
|
||||
|
||||
const title = 'Roadmap';
|
||||
const description = 'A list of future plans and goals, as well as past achievements and milestones.';
|
||||
|
||||
const withLanguage = (date: Date) => (language: string) => date.toLocaleDateString(language);
|
||||
|
||||
type Base = { icon: string; iconColor?: React.CSSProperties['color']; title: string; description: string };
|
||||
@@ -175,6 +180,38 @@ const withRelease = ({
|
||||
};
|
||||
|
||||
const roadmap: Item[] = [
|
||||
{
|
||||
done: false,
|
||||
icon: mdiFlash,
|
||||
iconColor: 'gold',
|
||||
title: 'Workflows',
|
||||
description: 'Automate tasks with workflows',
|
||||
getDateLabel: () => 'Planned for 2025',
|
||||
},
|
||||
{
|
||||
done: false,
|
||||
icon: mdiTableKey,
|
||||
iconColor: 'gray',
|
||||
title: 'Fine grained access controls',
|
||||
description: 'Granular access controls for users and api keys',
|
||||
getDateLabel: () => 'Planned for 2025',
|
||||
},
|
||||
{
|
||||
done: false,
|
||||
icon: mdiImageEdit,
|
||||
iconColor: 'rebeccapurple',
|
||||
title: 'Basic editor',
|
||||
description: 'Basic photo editing capabilities',
|
||||
getDateLabel: () => 'Planned for 2025',
|
||||
},
|
||||
{
|
||||
done: false,
|
||||
icon: mdiRocketLaunch,
|
||||
iconColor: 'indianred',
|
||||
title: 'Stable release',
|
||||
description: 'Immich goes stable',
|
||||
getDateLabel: () => 'Planned for early 2025',
|
||||
},
|
||||
{
|
||||
done: false,
|
||||
icon: mdiLockOutline,
|
||||
@@ -183,14 +220,6 @@ const roadmap: Item[] = [
|
||||
description: 'Private assets with extra protections',
|
||||
getDateLabel: () => 'Planned for 2024',
|
||||
},
|
||||
{
|
||||
done: false,
|
||||
icon: mdiRocketLaunch,
|
||||
iconColor: 'indianred',
|
||||
title: 'Stable release',
|
||||
description: 'Immich goes stable',
|
||||
getDateLabel: () => 'Planned for 2024',
|
||||
},
|
||||
{
|
||||
done: false,
|
||||
icon: mdiCloudUploadOutline,
|
||||
@@ -199,30 +228,6 @@ const roadmap: Item[] = [
|
||||
description: 'Rework background backups to be more reliable',
|
||||
getDateLabel: () => 'Planned for 2024',
|
||||
},
|
||||
{
|
||||
done: false,
|
||||
icon: mdiImageEdit,
|
||||
iconColor: 'rebeccapurple',
|
||||
title: 'Basic editor',
|
||||
description: 'Basic photo editing capabilities',
|
||||
getDateLabel: () => 'Planned for 2024',
|
||||
},
|
||||
{
|
||||
done: false,
|
||||
icon: mdiFlash,
|
||||
iconColor: 'gold',
|
||||
title: 'Workflows',
|
||||
description: 'Automate tasks with workflows',
|
||||
getDateLabel: () => 'Planned for 2024',
|
||||
},
|
||||
{
|
||||
done: false,
|
||||
icon: mdiTableKey,
|
||||
iconColor: 'gray',
|
||||
title: 'Fine grained access controls',
|
||||
description: 'Granular access controls for users and api keys',
|
||||
getDateLabel: () => 'Planned for 2024',
|
||||
},
|
||||
{
|
||||
done: false,
|
||||
icon: mdiCameraBurst,
|
||||
@@ -234,6 +239,20 @@ const roadmap: Item[] = [
|
||||
];
|
||||
|
||||
const milestones: Item[] = [
|
||||
withRelease({
|
||||
icon: mdiDatabaseOutline,
|
||||
iconColor: 'brown',
|
||||
title: 'Automatic database backups',
|
||||
description: 'Database backups are now integrated into the Immich server',
|
||||
release: 'v1.120.0',
|
||||
}),
|
||||
{
|
||||
icon: mdiStar,
|
||||
iconColor: 'gold',
|
||||
title: '50,000 Stars',
|
||||
description: 'Reached 50K Stars on GitHub!',
|
||||
getDateLabel: withLanguage(new Date(2024, 10, 1)),
|
||||
},
|
||||
withRelease({
|
||||
icon: mdiFaceRecognition,
|
||||
title: 'Metadata Face Import',
|
||||
@@ -853,14 +872,12 @@ const milestones: Item[] = [
|
||||
|
||||
export default function MilestonePage(): JSX.Element {
|
||||
return (
|
||||
<Layout title="Milestones" description="History of Immich">
|
||||
<Layout title={title} description={description}>
|
||||
<section className="my-8">
|
||||
<h1 className="md:text-6xl text-center mb-10 text-immich-primary dark:text-immich-dark-primary px-2">
|
||||
Roadmap
|
||||
{title}
|
||||
</h1>
|
||||
<p className="text-center text-xl px-2">
|
||||
A list of future plans and goals, as well as past achievements and milestones.
|
||||
</p>
|
||||
<p className="text-center text-xl px-2">{description}</p>
|
||||
<div className="flex justify-around mt-8 w-full max-w-full">
|
||||
<Timeline items={[...roadmap, ...milestones]} />
|
||||
</div>
|
||||
|
||||
36
docs/static/archived-versions.json
vendored
@@ -1,4 +1,40 @@
|
||||
[
|
||||
{
|
||||
"label": "v1.121.0",
|
||||
"url": "https://v1.121.0.archive.immich.app"
|
||||
},
|
||||
{
|
||||
"label": "v1.120.2",
|
||||
"url": "https://v1.120.2.archive.immich.app"
|
||||
},
|
||||
{
|
||||
"label": "v1.120.1",
|
||||
"url": "https://v1.120.1.archive.immich.app"
|
||||
},
|
||||
{
|
||||
"label": "v1.120.0",
|
||||
"url": "https://v1.120.0.archive.immich.app"
|
||||
},
|
||||
{
|
||||
"label": "v1.119.1",
|
||||
"url": "https://v1.119.1.archive.immich.app"
|
||||
},
|
||||
{
|
||||
"label": "v1.119.0",
|
||||
"url": "https://v1.119.0.archive.immich.app"
|
||||
},
|
||||
{
|
||||
"label": "v1.118.2",
|
||||
"url": "https://v1.118.2.archive.immich.app"
|
||||
},
|
||||
{
|
||||
"label": "v1.118.1",
|
||||
"url": "https://v1.118.1.archive.immich.app"
|
||||
},
|
||||
{
|
||||
"label": "v1.118.0",
|
||||
"url": "https://v1.118.0.archive.immich.app"
|
||||
},
|
||||
{
|
||||
"label": "v1.117.0",
|
||||
"url": "https://v1.117.0.archive.immich.app"
|
||||
|
||||
@@ -1 +1 @@
|
||||
20.18.0
|
||||
22.11.0
|
||||
|
||||
@@ -19,7 +19,7 @@ services:
|
||||
- DB_PASSWORD=postgres
|
||||
- DB_DATABASE_NAME=immich
|
||||
- IMMICH_MACHINE_LEARNING_ENABLED=false
|
||||
- IMMICH_METRICS=true
|
||||
- IMMICH_TELEMETRY_INCLUDE=all
|
||||
- IMMICH_ENV=testing
|
||||
- IMMICH_PORT=2285
|
||||
- IMMICH_IGNORE_MOUNT_CHECK_ERRORS=true
|
||||
@@ -34,7 +34,7 @@ services:
|
||||
- 2285:2285
|
||||
|
||||
redis:
|
||||
image: redis:6.2-alpine@sha256:2ba50e1ac3a0ea17b736ce9db2b0a9f6f8b85d4c27d5f5accc6a416d8f42c6d5
|
||||
image: redis:6.2-alpine@sha256:eaba718fecd1196d88533de7ba49bf903ad33664a92debb24660a922ecd9cac8
|
||||
|
||||
database:
|
||||
image: tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0
|
||||
|
||||
745
e2e/package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "immich-e2e",
|
||||
"version": "1.117.0",
|
||||
"version": "1.121.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
@@ -25,7 +25,7 @@
|
||||
"@immich/sdk": "file:../open-api/typescript-sdk",
|
||||
"@playwright/test": "^1.44.1",
|
||||
"@types/luxon": "^3.4.2",
|
||||
"@types/node": "^20.16.10",
|
||||
"@types/node": "^22.9.0",
|
||||
"@types/oidc-provider": "^8.5.1",
|
||||
"@types/pg": "^8.11.0",
|
||||
"@types/pngjs": "^6.0.4",
|
||||
@@ -53,6 +53,6 @@
|
||||
"vitest": "^2.0.5"
|
||||
},
|
||||
"volta": {
|
||||
"node": "20.18.0"
|
||||
"node": "22.11.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,6 +141,7 @@ describe('/albums', () => {
|
||||
expect(body).toEqual({
|
||||
...user1Albums[0],
|
||||
assets: [expect.objectContaining({ isFavorite: false })],
|
||||
lastModifiedAssetTimestamp: expect.any(String),
|
||||
});
|
||||
});
|
||||
|
||||
@@ -297,6 +298,7 @@ describe('/albums', () => {
|
||||
expect(body).toEqual({
|
||||
...user1Albums[0],
|
||||
assets: [expect.objectContaining({ id: user1Albums[0].assets[0].id })],
|
||||
lastModifiedAssetTimestamp: expect.any(String),
|
||||
});
|
||||
});
|
||||
|
||||
@@ -327,6 +329,7 @@ describe('/albums', () => {
|
||||
expect(body).toEqual({
|
||||
...user1Albums[0],
|
||||
assets: [expect.objectContaining({ id: user1Albums[0].assets[0].id })],
|
||||
lastModifiedAssetTimestamp: expect.any(String),
|
||||
});
|
||||
});
|
||||
|
||||
@@ -340,6 +343,7 @@ describe('/albums', () => {
|
||||
...user1Albums[0],
|
||||
assets: [],
|
||||
assetCount: 1,
|
||||
lastModifiedAssetTimestamp: expect.any(String),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1060,7 +1060,7 @@ describe('/asset', () => {
|
||||
expected: {
|
||||
type: AssetTypeEnum.Image,
|
||||
originalFileName: 'philadelphia.nef',
|
||||
fileCreatedAt: '2016-09-22T22:10:29.060Z',
|
||||
fileCreatedAt: '2016-09-22T21:10:29.060Z',
|
||||
exifInfo: {
|
||||
make: 'NIKON CORPORATION',
|
||||
model: 'NIKON D700',
|
||||
@@ -1069,11 +1069,11 @@ describe('/asset', () => {
|
||||
focalLength: 85,
|
||||
iso: 200,
|
||||
fileSizeInByte: 15_856_335,
|
||||
dateTimeOriginal: '2016-09-22T22:10:29.060Z',
|
||||
dateTimeOriginal: '2016-09-22T21:10:29.060Z',
|
||||
latitude: null,
|
||||
longitude: null,
|
||||
orientation: '1',
|
||||
timeZone: 'UTC-5',
|
||||
timeZone: 'UTC-4',
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1148,6 +1148,78 @@ describe('/asset', () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: 'formats/raw/Canon/PowerShot_G12.CR2',
|
||||
expected: {
|
||||
type: AssetTypeEnum.Image,
|
||||
originalFileName: 'PowerShot_G12.CR2',
|
||||
fileCreatedAt: '2015-12-27T09:55:40.000Z',
|
||||
exifInfo: {
|
||||
make: 'Canon',
|
||||
model: 'Canon PowerShot G12',
|
||||
exifImageHeight: 2736,
|
||||
exifImageWidth: 3648,
|
||||
exposureTime: '1/1000',
|
||||
fNumber: 4,
|
||||
focalLength: 18.098,
|
||||
iso: 80,
|
||||
lensModel: null,
|
||||
fileSizeInByte: 11_113_617,
|
||||
dateTimeOriginal: '2015-12-27T09:55:40.000Z',
|
||||
latitude: null,
|
||||
longitude: null,
|
||||
orientation: '1',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: 'formats/raw/Fujifilm/X100V_compressed.RAF',
|
||||
expected: {
|
||||
type: AssetTypeEnum.Image,
|
||||
originalFileName: 'X100V_compressed.RAF',
|
||||
fileCreatedAt: '2024-10-12T21:01:01.000Z',
|
||||
exifInfo: {
|
||||
make: 'FUJIFILM',
|
||||
model: 'X100V',
|
||||
exifImageHeight: 4160,
|
||||
exifImageWidth: 6240,
|
||||
exposureTime: '1/4000',
|
||||
fNumber: 16,
|
||||
focalLength: 23,
|
||||
iso: 160,
|
||||
lensModel: null,
|
||||
fileSizeInByte: 13_551_312,
|
||||
dateTimeOriginal: '2024-10-12T21:01:01.000Z',
|
||||
latitude: null,
|
||||
longitude: null,
|
||||
orientation: '6',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: 'formats/raw/Ricoh/GR3/Ricoh_GR3-450.DNG',
|
||||
expected: {
|
||||
type: AssetTypeEnum.Image,
|
||||
originalFileName: 'Ricoh_GR3-450.DNG',
|
||||
fileCreatedAt: '2024-06-08T13:48:39.000Z',
|
||||
exifInfo: {
|
||||
dateTimeOriginal: '2024-06-08T13:48:39.000Z',
|
||||
exifImageHeight: 4064,
|
||||
exifImageWidth: 6112,
|
||||
exposureTime: '1/400',
|
||||
fNumber: 5,
|
||||
fileSizeInByte: 31_175_472,
|
||||
focalLength: 18.3,
|
||||
iso: 100,
|
||||
latitude: 36.613_24,
|
||||
lensModel: 'GR LENS 18.3mm F2.8',
|
||||
longitude: -121.897_85,
|
||||
make: 'RICOH IMAGING COMPANY, LTD.',
|
||||
model: 'RICOH GR III',
|
||||
orientation: '1',
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
it(`should upload and generate a thumbnail for different file types`, async () => {
|
||||
|
||||
@@ -633,6 +633,29 @@ describe('/libraries', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("should fail if path isn't absolute", async () => {
|
||||
const pathToTest = `relative/path`;
|
||||
|
||||
const cwd = process.cwd();
|
||||
// Create directory in cwd
|
||||
utils.createDirectory(`${cwd}/${pathToTest}`);
|
||||
|
||||
const response = await utils.validateLibrary(admin.accessToken, library.id, {
|
||||
importPaths: [pathToTest],
|
||||
});
|
||||
|
||||
utils.removeDirectory(`${cwd}/${pathToTest}`);
|
||||
|
||||
expect(response.importPaths?.length).toEqual(1);
|
||||
const pathResponse = response?.importPaths?.at(0);
|
||||
|
||||
expect(pathResponse).toEqual({
|
||||
importPath: pathToTest,
|
||||
isValid: false,
|
||||
message: expect.stringMatching('Import path must be absolute, try /usr/src/app/relative/path'),
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail if path is a file', async () => {
|
||||
const pathToTest = `${testAssetDirInternal}/albums/nature/el_torcal_rocks.jpg`;
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@ const authServer = {
|
||||
external: 'http://127.0.0.1:3000',
|
||||
};
|
||||
|
||||
const mobileOverrideRedirectUri = 'https://photos.immich.app/oauth/mobile-redirect';
|
||||
|
||||
const redirect = async (url: string, cookies?: string[]) => {
|
||||
const { headers } = await request(url)
|
||||
.get('/')
|
||||
@@ -24,8 +26,8 @@ const redirect = async (url: string, cookies?: string[]) => {
|
||||
return { cookies: (headers['set-cookie'] as unknown as string[]) || [], location: headers.location };
|
||||
};
|
||||
|
||||
const loginWithOAuth = async (sub: OAuthUser | string) => {
|
||||
const { url } = await startOAuth({ oAuthConfigDto: { redirectUri: `${baseUrl}/auth/login` } });
|
||||
const loginWithOAuth = async (sub: OAuthUser | string, redirectUri?: string) => {
|
||||
const { url } = await startOAuth({ oAuthConfigDto: { redirectUri: redirectUri ?? `${baseUrl}/auth/login` } });
|
||||
|
||||
// login
|
||||
const response1 = await redirect(url.replace(authServer.internal, authServer.external));
|
||||
@@ -255,4 +257,50 @@ describe(`/oauth`, () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('mobile redirect override', () => {
|
||||
beforeAll(async () => {
|
||||
await setupOAuth(admin.accessToken, {
|
||||
enabled: true,
|
||||
clientId: OAuthClient.DEFAULT,
|
||||
clientSecret: OAuthClient.DEFAULT,
|
||||
buttonText: 'Login with Immich',
|
||||
storageLabelClaim: 'immich_username',
|
||||
mobileOverrideEnabled: true,
|
||||
mobileRedirectUri: mobileOverrideRedirectUri,
|
||||
});
|
||||
});
|
||||
|
||||
it('should return the mobile redirect uri', async () => {
|
||||
const { status, body } = await request(app)
|
||||
.post('/oauth/authorize')
|
||||
.send({ redirectUri: 'app.immich:///oauth-callback' });
|
||||
expect(status).toBe(201);
|
||||
expect(body).toEqual({ url: expect.stringContaining(`${authServer.internal}/auth?`) });
|
||||
|
||||
const params = new URL(body.url).searchParams;
|
||||
expect(params.get('client_id')).toBe('client-default');
|
||||
expect(params.get('response_type')).toBe('code');
|
||||
expect(params.get('redirect_uri')).toBe(mobileOverrideRedirectUri);
|
||||
expect(params.get('state')).toBeDefined();
|
||||
});
|
||||
|
||||
it('should auto register the user by default', async () => {
|
||||
const url = await loginWithOAuth('oauth-mobile-override', 'app.immich:///oauth-callback');
|
||||
expect(url).toEqual(expect.stringContaining(mobileOverrideRedirectUri));
|
||||
|
||||
// simulate redirecting back to mobile app
|
||||
const redirectUri = url.replace(mobileOverrideRedirectUri, 'app.immich:///oauth-callback');
|
||||
|
||||
const { status, body } = await request(app).post('/oauth/callback').send({ url: redirectUri });
|
||||
expect(status).toBe(201);
|
||||
expect(body).toMatchObject({
|
||||
accessToken: expect.any(String),
|
||||
isAdmin: false,
|
||||
name: 'OAuth User',
|
||||
userEmail: 'oauth-mobile-override@immich.app',
|
||||
userId: expect.any(String),
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -473,10 +473,7 @@ describe('/search', () => {
|
||||
.get('/search/explore')
|
||||
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||
expect(status).toBe(200);
|
||||
expect(body).toEqual([
|
||||
{ fieldName: 'exifInfo.city', items: [] },
|
||||
{ fieldName: 'smartInfo.tags', items: [] },
|
||||
]);
|
||||
expect(body).toEqual([{ fieldName: 'exifInfo.city', items: [] }]);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -163,11 +163,15 @@ describe('/server', () => {
|
||||
expect(body).toEqual({
|
||||
photos: 0,
|
||||
usage: 0,
|
||||
usagePhotos: 0,
|
||||
usageVideos: 0,
|
||||
usageByUser: [
|
||||
{
|
||||
quotaSizeInBytes: null,
|
||||
photos: 0,
|
||||
usage: 0,
|
||||
usagePhotos: 0,
|
||||
usageVideos: 0,
|
||||
userName: 'Immich Admin',
|
||||
userId: admin.userId,
|
||||
videos: 0,
|
||||
@@ -176,6 +180,8 @@ describe('/server', () => {
|
||||
quotaSizeInBytes: null,
|
||||
photos: 0,
|
||||
usage: 0,
|
||||
usagePhotos: 0,
|
||||
usageVideos: 0,
|
||||
userName: 'User 1',
|
||||
userId: nonAdmin.userId,
|
||||
videos: 0,
|
||||
|
||||
@@ -103,7 +103,7 @@ describe(`immich upload`, () => {
|
||||
describe(`immich upload /path/to/file.jpg`, () => {
|
||||
it('should upload a single file', async () => {
|
||||
const { stderr, stdout, exitCode } = await immichCli(['upload', `${testAssetDir}/albums/nature/silver_fir.jpg`]);
|
||||
expect(stderr).toBe('');
|
||||
expect(stderr).toContain('{message}');
|
||||
expect(stdout.split('\n')).toEqual(
|
||||
expect.arrayContaining([expect.stringContaining('Successfully uploaded 1 new asset')]),
|
||||
);
|
||||
@@ -126,7 +126,7 @@ describe(`immich upload`, () => {
|
||||
const expectedCount = Object.entries(files).filter((entry) => entry[1]).length;
|
||||
|
||||
const { stderr, stdout, exitCode } = await immichCli(['upload', ...commandLine]);
|
||||
expect(stderr).toBe('');
|
||||
expect(stderr).toContain('{message}');
|
||||
expect(stdout.split('\n')).toEqual(
|
||||
expect.arrayContaining([expect.stringContaining(`Successfully uploaded ${expectedCount} new asset`)]),
|
||||
);
|
||||
@@ -154,7 +154,7 @@ describe(`immich upload`, () => {
|
||||
cpSync(`${testAssetDir}/albums/nature/silver_fir.jpg`, testPaths[1]);
|
||||
|
||||
const { stderr, stdout, exitCode } = await immichCli(['upload', ...testPaths]);
|
||||
expect(stderr).toBe('');
|
||||
expect(stderr).toContain('{message}');
|
||||
expect(stdout.split('\n')).toEqual(
|
||||
expect.arrayContaining([expect.stringContaining('Successfully uploaded 2 new assets')]),
|
||||
);
|
||||
@@ -169,7 +169,7 @@ describe(`immich upload`, () => {
|
||||
|
||||
it('should skip a duplicate file', async () => {
|
||||
const first = await immichCli(['upload', `${testAssetDir}/albums/nature/silver_fir.jpg`]);
|
||||
expect(first.stderr).toBe('');
|
||||
expect(first.stderr).toContain('{message}');
|
||||
expect(first.stdout.split('\n')).toEqual(
|
||||
expect.arrayContaining([expect.stringContaining('Successfully uploaded 1 new asset')]),
|
||||
);
|
||||
@@ -179,7 +179,7 @@ describe(`immich upload`, () => {
|
||||
expect(assets.total).toBe(1);
|
||||
|
||||
const second = await immichCli(['upload', `${testAssetDir}/albums/nature/silver_fir.jpg`]);
|
||||
expect(second.stderr).toBe('');
|
||||
expect(second.stderr).toContain('{message}');
|
||||
expect(second.stdout.split('\n')).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.stringContaining('Found 0 new files and 1 duplicate'),
|
||||
@@ -205,7 +205,7 @@ describe(`immich upload`, () => {
|
||||
`${testAssetDir}/albums/nature/silver_fir.jpg`,
|
||||
'--dry-run',
|
||||
]);
|
||||
expect(stderr).toBe('');
|
||||
expect(stderr).toContain('{message}');
|
||||
expect(stdout.split('\n')).toEqual(
|
||||
expect.arrayContaining([expect.stringContaining('Would have uploaded 1 asset')]),
|
||||
);
|
||||
@@ -217,7 +217,7 @@ describe(`immich upload`, () => {
|
||||
|
||||
it('dry run should handle duplicates', async () => {
|
||||
const first = await immichCli(['upload', `${testAssetDir}/albums/nature/silver_fir.jpg`]);
|
||||
expect(first.stderr).toBe('');
|
||||
expect(first.stderr).toContain('{message}');
|
||||
expect(first.stdout.split('\n')).toEqual(
|
||||
expect.arrayContaining([expect.stringContaining('Successfully uploaded 1 new asset')]),
|
||||
);
|
||||
@@ -227,7 +227,7 @@ describe(`immich upload`, () => {
|
||||
expect(assets.total).toBe(1);
|
||||
|
||||
const second = await immichCli(['upload', `${testAssetDir}/albums/nature/`, '--dry-run']);
|
||||
expect(second.stderr).toBe('');
|
||||
expect(second.stderr).toContain('{message}');
|
||||
expect(second.stdout.split('\n')).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.stringContaining('Found 8 new files and 1 duplicate'),
|
||||
@@ -241,7 +241,7 @@ describe(`immich upload`, () => {
|
||||
describe('immich upload --recursive', () => {
|
||||
it('should upload a folder recursively', async () => {
|
||||
const { stderr, stdout, exitCode } = await immichCli(['upload', `${testAssetDir}/albums/nature/`, '--recursive']);
|
||||
expect(stderr).toBe('');
|
||||
expect(stderr).toContain('{message}');
|
||||
expect(stdout.split('\n')).toEqual(
|
||||
expect.arrayContaining([expect.stringContaining('Successfully uploaded 9 new assets')]),
|
||||
);
|
||||
@@ -267,7 +267,7 @@ describe(`immich upload`, () => {
|
||||
expect.stringContaining('Successfully updated 9 assets'),
|
||||
]),
|
||||
);
|
||||
expect(stderr).toBe('');
|
||||
expect(stderr).toContain('{message}');
|
||||
expect(exitCode).toBe(0);
|
||||
|
||||
const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) });
|
||||
@@ -283,7 +283,7 @@ describe(`immich upload`, () => {
|
||||
expect(response1.stdout.split('\n')).toEqual(
|
||||
expect.arrayContaining([expect.stringContaining('Successfully uploaded 9 new assets')]),
|
||||
);
|
||||
expect(response1.stderr).toBe('');
|
||||
expect(response1.stderr).toContain('{message}');
|
||||
expect(response1.exitCode).toBe(0);
|
||||
|
||||
const assets1 = await getAssetStatistics({}, { headers: asKeyAuth(key) });
|
||||
@@ -299,7 +299,7 @@ describe(`immich upload`, () => {
|
||||
expect.stringContaining('Successfully updated 9 assets'),
|
||||
]),
|
||||
);
|
||||
expect(response2.stderr).toBe('');
|
||||
expect(response2.stderr).toContain('{message}');
|
||||
expect(response2.exitCode).toBe(0);
|
||||
|
||||
const assets2 = await getAssetStatistics({}, { headers: asKeyAuth(key) });
|
||||
@@ -325,7 +325,7 @@ describe(`immich upload`, () => {
|
||||
expect.stringContaining('Would have updated albums of 9 assets'),
|
||||
]),
|
||||
);
|
||||
expect(stderr).toBe('');
|
||||
expect(stderr).toContain('{message}');
|
||||
expect(exitCode).toBe(0);
|
||||
|
||||
const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) });
|
||||
@@ -351,7 +351,7 @@ describe(`immich upload`, () => {
|
||||
expect.stringContaining('Successfully updated 9 assets'),
|
||||
]),
|
||||
);
|
||||
expect(stderr).toBe('');
|
||||
expect(stderr).toContain('{message}');
|
||||
expect(exitCode).toBe(0);
|
||||
|
||||
const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) });
|
||||
@@ -377,7 +377,7 @@ describe(`immich upload`, () => {
|
||||
expect.stringContaining('Would have updated albums of 9 assets'),
|
||||
]),
|
||||
);
|
||||
expect(stderr).toBe('');
|
||||
expect(stderr).toContain('{message}');
|
||||
expect(exitCode).toBe(0);
|
||||
|
||||
const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) });
|
||||
@@ -408,7 +408,7 @@ describe(`immich upload`, () => {
|
||||
expect.stringContaining('Deleting assets that have been uploaded'),
|
||||
]),
|
||||
);
|
||||
expect(stderr).toBe('');
|
||||
expect(stderr).toContain('{message}');
|
||||
expect(exitCode).toBe(0);
|
||||
|
||||
const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) });
|
||||
@@ -434,7 +434,7 @@ describe(`immich upload`, () => {
|
||||
expect.stringContaining('Would have deleted 9 local assets'),
|
||||
]),
|
||||
);
|
||||
expect(stderr).toBe('');
|
||||
expect(stderr).toContain('{message}');
|
||||
expect(exitCode).toBe(0);
|
||||
|
||||
const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) });
|
||||
@@ -493,7 +493,7 @@ describe(`immich upload`, () => {
|
||||
'2',
|
||||
]);
|
||||
|
||||
expect(stderr).toBe('');
|
||||
expect(stderr).toContain('{message}');
|
||||
expect(stdout.split('\n')).toEqual(
|
||||
expect.arrayContaining([
|
||||
'Found 9 new files and 0 duplicates',
|
||||
@@ -534,7 +534,7 @@ describe(`immich upload`, () => {
|
||||
'silver_fir.jpg',
|
||||
]);
|
||||
|
||||
expect(stderr).toBe('');
|
||||
expect(stderr).toContain('{message}');
|
||||
expect(stdout.split('\n')).toEqual(
|
||||
expect.arrayContaining([
|
||||
'Found 8 new files and 0 duplicates',
|
||||
@@ -555,7 +555,7 @@ describe(`immich upload`, () => {
|
||||
'!(*_*_*).jpg',
|
||||
]);
|
||||
|
||||
expect(stderr).toBe('');
|
||||
expect(stderr).toContain('{message}');
|
||||
expect(stdout.split('\n')).toEqual(
|
||||
expect.arrayContaining([
|
||||
'Found 1 new files and 0 duplicates',
|
||||
@@ -577,7 +577,7 @@ describe(`immich upload`, () => {
|
||||
'--dry-run',
|
||||
]);
|
||||
|
||||
expect(stderr).toBe('');
|
||||
expect(stderr).toContain('{message}');
|
||||
expect(stdout.split('\n')).toEqual(
|
||||
expect.arrayContaining([
|
||||
'Found 8 new files and 0 duplicates',
|
||||
|
||||
@@ -9,9 +9,11 @@ describe(`immich-admin`, () => {
|
||||
|
||||
describe('list-users', () => {
|
||||
it('should list the admin user', async () => {
|
||||
const { stdout, stderr, exitCode } = await immichAdmin(['list-users']).promise;
|
||||
const { stdout, exitCode } = await immichAdmin(['list-users']).promise;
|
||||
expect(exitCode).toBe(0);
|
||||
expect(stderr).toBe('');
|
||||
|
||||
// TODO: Vitest needs upgrade to Node 22.x to fix the failed check
|
||||
// expect(stderr).toBe('');
|
||||
expect(stdout).toContain("email: 'admin@immich.cloud'");
|
||||
expect(stdout).toContain("name: 'Immich Admin'");
|
||||
});
|
||||
@@ -29,9 +31,10 @@ describe(`immich-admin`, () => {
|
||||
}
|
||||
});
|
||||
|
||||
const { stderr, stdout, exitCode } = await promise;
|
||||
const { stdout, exitCode } = await promise;
|
||||
expect(exitCode).toBe(0);
|
||||
expect(stderr).toBe('');
|
||||
// TODO: Vitest needs upgrade to Node 22.x to fix the failed check
|
||||
// expect(stderr).toBe('');
|
||||
expect(stdout).toContain('The admin password has been updated to:');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -50,6 +50,7 @@ const getClaims = (sub: string) => claims.find((user) => user.sub === sub) || wi
|
||||
const setup = async () => {
|
||||
const { privateKey, publicKey } = await generateKeyPair('RS256');
|
||||
|
||||
const redirectUris = ['http://127.0.0.1:2285/auth/login', 'https://photos.immich.app/oauth/mobile-redirect'];
|
||||
const port = 3000;
|
||||
const host = '0.0.0.0';
|
||||
const oidc = new Provider(`http://${host}:${port}`, {
|
||||
@@ -86,14 +87,14 @@ const setup = async () => {
|
||||
{
|
||||
client_id: OAuthClient.DEFAULT,
|
||||
client_secret: OAuthClient.DEFAULT,
|
||||
redirect_uris: ['http://127.0.0.1:2285/auth/login'],
|
||||
redirect_uris: redirectUris,
|
||||
grant_types: ['authorization_code'],
|
||||
response_types: ['code'],
|
||||
},
|
||||
{
|
||||
client_id: OAuthClient.RS256_TOKENS,
|
||||
client_secret: OAuthClient.RS256_TOKENS,
|
||||
redirect_uris: ['http://127.0.0.1:2285/auth/login'],
|
||||
redirect_uris: redirectUris,
|
||||
grant_types: ['authorization_code'],
|
||||
id_token_signed_response_alg: 'RS256',
|
||||
jwks: { keys: [await exportJWK(publicKey)] },
|
||||
@@ -101,7 +102,7 @@ const setup = async () => {
|
||||
{
|
||||
client_id: OAuthClient.RS256_PROFILE,
|
||||
client_secret: OAuthClient.RS256_PROFILE,
|
||||
redirect_uris: ['http://127.0.0.1:2285/auth/login'],
|
||||
redirect_uris: redirectUris,
|
||||
grant_types: ['authorization_code'],
|
||||
userinfo_signed_response_alg: 'RS256',
|
||||
jwks: { keys: [await exportJWK(publicKey)] },
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
PersonCreateDto,
|
||||
SharedLinkCreateDto,
|
||||
UserAdminCreateDto,
|
||||
UserPreferencesUpdateDto,
|
||||
ValidateLibraryDto,
|
||||
checkExistingAssets,
|
||||
createAlbum,
|
||||
@@ -19,6 +20,7 @@ import {
|
||||
createPartner,
|
||||
createPerson,
|
||||
createSharedLink,
|
||||
createStack,
|
||||
createUserAdmin,
|
||||
deleteAssets,
|
||||
getAllJobsStatus,
|
||||
@@ -28,10 +30,13 @@ import {
|
||||
searchMetadata,
|
||||
setBaseUrl,
|
||||
signUpAdmin,
|
||||
tagAssets,
|
||||
updateAdminOnboarding,
|
||||
updateAlbumUser,
|
||||
updateAssets,
|
||||
updateConfig,
|
||||
updateMyPreferences,
|
||||
upsertTags,
|
||||
validate,
|
||||
} from '@immich/sdk';
|
||||
import { BrowserContext } from '@playwright/test';
|
||||
@@ -444,6 +449,18 @@ export const utils = {
|
||||
|
||||
createPartner: (accessToken: string, id: string) => createPartner({ id }, { headers: asBearerAuth(accessToken) }),
|
||||
|
||||
updateMyPreferences: (accessToken: string, userPreferencesUpdateDto: UserPreferencesUpdateDto) =>
|
||||
updateMyPreferences({ userPreferencesUpdateDto }, { headers: asBearerAuth(accessToken) }),
|
||||
|
||||
createStack: (accessToken: string, assetIds: string[]) =>
|
||||
createStack({ stackCreateDto: { assetIds } }, { headers: asBearerAuth(accessToken) }),
|
||||
|
||||
upsertTags: (accessToken: string, tags: string[]) =>
|
||||
upsertTags({ tagUpsertDto: { tags } }, { headers: asBearerAuth(accessToken) }),
|
||||
|
||||
tagAssets: (accessToken: string, tagId: string, assetIds: string[]) =>
|
||||
tagAssets({ id: tagId, bulkIdsDto: { ids: assetIds } }, { headers: asBearerAuth(accessToken) }),
|
||||
|
||||
setAuthCookies: async (context: BrowserContext, accessToken: string, domain = '127.0.0.1') =>
|
||||
await context.addCookies([
|
||||
{
|
||||
|
||||
66
e2e/src/web/specs/asset-viewer/stack.e2e-spec.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { AssetMediaResponseDto, LoginResponseDto } from '@immich/sdk';
|
||||
import { expect, Page, test } from '@playwright/test';
|
||||
import { utils } from 'src/utils';
|
||||
|
||||
async function ensureDetailPanelVisible(page: Page) {
|
||||
await page.waitForSelector('#immich-asset-viewer');
|
||||
|
||||
const isVisible = await page.locator('#detail-panel').isVisible();
|
||||
if (!isVisible) {
|
||||
await page.keyboard.press('i');
|
||||
await page.waitForSelector('#detail-panel');
|
||||
}
|
||||
}
|
||||
|
||||
test.describe('Asset Viewer stack', () => {
|
||||
let admin: LoginResponseDto;
|
||||
let assetOne: AssetMediaResponseDto;
|
||||
let assetTwo: AssetMediaResponseDto;
|
||||
|
||||
test.beforeAll(async () => {
|
||||
utils.initSdk();
|
||||
await utils.resetDatabase();
|
||||
admin = await utils.adminSetup();
|
||||
await utils.updateMyPreferences(admin.accessToken, { tags: { enabled: true } });
|
||||
|
||||
assetOne = await utils.createAsset(admin.accessToken);
|
||||
assetTwo = await utils.createAsset(admin.accessToken);
|
||||
await utils.createStack(admin.accessToken, [assetOne.id, assetTwo.id]);
|
||||
|
||||
const tags = await utils.upsertTags(admin.accessToken, ['test/1', 'test/2']);
|
||||
const tagOne = tags.find((tag) => tag.value === 'test/1')!;
|
||||
const tagTwo = tags.find((tag) => tag.value === 'test/2')!;
|
||||
await utils.tagAssets(admin.accessToken, tagOne.id, [assetOne.id]);
|
||||
await utils.tagAssets(admin.accessToken, tagTwo.id, [assetTwo.id]);
|
||||
});
|
||||
|
||||
test('stack slideshow is visible', async ({ page, context }) => {
|
||||
await utils.setAuthCookies(context, admin.accessToken);
|
||||
await page.goto(`/photos/${assetOne.id}`);
|
||||
|
||||
const stackAssets = page.locator('#stack-slideshow [data-asset]');
|
||||
await expect(stackAssets.first()).toBeVisible();
|
||||
await expect(stackAssets.nth(1)).toBeVisible();
|
||||
});
|
||||
|
||||
test('tags of primary asset are visible', async ({ page, context }) => {
|
||||
await utils.setAuthCookies(context, admin.accessToken);
|
||||
await page.goto(`/photos/${assetOne.id}`);
|
||||
await ensureDetailPanelVisible(page);
|
||||
|
||||
const tags = page.getByTestId('detail-panel-tags').getByRole('link');
|
||||
await expect(tags.first()).toHaveText('test/1');
|
||||
});
|
||||
|
||||
test('tags of second asset are visible', async ({ page, context }) => {
|
||||
await utils.setAuthCookies(context, admin.accessToken);
|
||||
await page.goto(`/photos/${assetOne.id}`);
|
||||
await ensureDetailPanelVisible(page);
|
||||
|
||||
const stackAssets = page.locator('#stack-slideshow [data-asset]');
|
||||
await stackAssets.nth(1).click();
|
||||
|
||||
const tags = page.getByTestId('detail-panel-tags').getByRole('link');
|
||||
await expect(tags.first()).toHaveText('test/2');
|
||||
});
|
||||
});
|
||||
@@ -34,6 +34,11 @@
|
||||
"authentication_settings_disable_all": "هل أنت متأكد أنك تريد تعطيل جميع وسائل تسجيل الدخول؟ سيتم تعطيل تسجيل الدخول بالكامل.",
|
||||
"authentication_settings_reenable": "لإعادة التفعيل، استخدم <link>أمر الخادم</link>.",
|
||||
"background_task_job": "المهام الخلفية",
|
||||
"backup_database": "قاعدة البيانات الاحتياطية",
|
||||
"backup_database_enable_description": "تمكين النسخ الاحتياطي لقاعدة البيانات",
|
||||
"backup_keep_last_amount": "مقدار النسخ الاحتياطية السابقة للاحتفاظ بها",
|
||||
"backup_settings": "إعدادات النسخ الاحتياطي",
|
||||
"backup_settings_description": "إدارة إعدادات النسخ الاحتياطي لقاعدة البيانات",
|
||||
"check_all": "اختر الكل",
|
||||
"cleared_jobs": "تم إخلاء مهام: {job}",
|
||||
"config_set_by_file": "الإعدادات حاليًا معينة عن طريق ملف الاعدادات",
|
||||
@@ -43,16 +48,17 @@
|
||||
"confirm_reprocess_all_faces": "هل أنت متأكد أنك تريد إعادة معالجة جميع الوجوه؟ سيخلي هذا كل الأشخاص الذين سَميتَهم.",
|
||||
"confirm_user_password_reset": "هل أنت متأكد أنك تريد إعادة تعيين كلمة مرور {user}؟",
|
||||
"create_job": "إنشاء وظيفة",
|
||||
"crontab_guru": "",
|
||||
"cron_expression": "تعبير Cron",
|
||||
"cron_expression_description": "اضبط الفاصل الزمني للفحص باستخدام تنسيق cron. لمزيد من المعلومات يُرجى الرجوع إلى <link>Crontab Guru</link> على سبيل المثال",
|
||||
"cron_expression_presets": "الإعدادات المسبقة لتعبير Cron",
|
||||
"disable_login": "تعطيل تسجيل الدخول",
|
||||
"disabled": "",
|
||||
"duplicate_detection_job_description": "بدء التعلم الآلي على المحتوى للعثور على الصور المتشابهة. يعتمد على البحث الذكي",
|
||||
"exclusion_pattern_description": "تتيح لك أنماط الاستبعاد تجاهل الملفات والمجلدات عند فحص مكتبتك. يعد هذا مفيدًا إذا كان لديك مجلدات تحتوي على ملفات لا تريد استيرادها، مثل ملفات RAW.",
|
||||
"external_library_created_at": "مكتبة خارجية (أُنشئت في {date})",
|
||||
"external_library_management": "إدارة المكتبة الخارجية",
|
||||
"face_detection": "إكتشاف الوجوه",
|
||||
"face_detection_description": "اكتشف الوجوه في المحتويات باستخدام التعلم الآلي. بالنسبة للفيديوهات، سيتم فقط استخدام الصورة المصغرة. خيار \"الكل\" يعيد معالجة كل المحتويات. خيار \"مفقود\" يضع في قائمة الإنتظار المحتويات التي لم تعالج بعد. سيتم وضع الوجوه المكتشفة في قائمة إنتظار التعرف على الوجه بعد اكتمال اكتشاف الوجه، مما يجمعها بأشخاص موجودين أو جدد.",
|
||||
"facial_recognition_job_description": "تجميع الوجوه المكتشفة كأشخاص. يتم تنفيذ هذه الخطوة بعد اكتمال اكتشاف الوجه. خيار \"الكل\" يعيد تجميع جميع الوجوه. خيار \"المفقود\" يضع في قائمة الانتظار الوجوه التي لم يتم تعيين شخص لها.",
|
||||
"face_detection_description": "اكتشف الوجوه في الأصول باستخدام التعلم الآلي. بالنسبة لمقاطع الفيديو، يتم اعتبار الصورة المصغرة فقط. \"تحديث\" (إعادة) معالجة جميع الأصول. \"إعادة تعيين\" تمسح أيضًا جميع بيانات الوجوه الحالية. \"مفقود\" يضع الأصول التي لم تتم معالجتها بعد في قائمة الانتظار. سيتم وضع الوجوه المكتشفة في قائمة الانتظار للتعرف على الوجه بعد اكتمال اكتشاف الوجه، وتجميعها في أشخاص موجودين أو جدد.",
|
||||
"facial_recognition_job_description": "تجميع الوجوه المكتشفة كأشخاص. يتم تنفيذ هذه الخطوة بعد اكتمال اكتشاف الوجه. خيار \"إعادة التعيين\" يعيد تجميع جميع الوجوه. خيار \"المفقود\" يضع في قائمة الانتظار الوجوه التي لم يتم تعيين شخص لها.",
|
||||
"failed_job_command": "فشل الأمر {command} للمهمة: {job}",
|
||||
"force_delete_user_warning": "تحذير: سيؤدي ذلك إلى إزالة المستخدم وجميع محتوياته على الفور. لا يمكن التراجع عن هذا الإجراء ولا يمكن استرداد الملفات.",
|
||||
"forcing_refresh_library_files": "إجبار التحديث لجميع ملفات المكتبة",
|
||||
@@ -63,22 +69,15 @@
|
||||
"image_prefer_wide_gamut": "تفضيل نطاق الألوان الواسع",
|
||||
"image_prefer_wide_gamut_setting_description": "استخدم Display P3 للصور المصغرة. يحافظ هذا على حيوية الصور ذات مساحات الألوان الواسعة بشكل أفضل، ولكن قد تظهر الصور بشكل مختلف على الأجهزة القديمة ذات إصدار متصفح قديم. يتم الاحتفاظ بصور sRGB بتنسيق sRGB لتجنب تغيرات اللون.",
|
||||
"image_preview_description": "صورة متوسطة الحجم مع بيانات وصفية مجردة، تُستخدم عند عرض أصل واحد وللتعلم الآلي",
|
||||
"image_preview_format": "تنسيق المعاينة",
|
||||
"image_preview_quality_description": "جودة المعاينة من 1 إلى 100. كلما كانت القيمة أعلى كان ذلك أفضل، ولكنها تنتج ملفات أكبر وقد تقلل من استجابة التطبيق. قد يؤثر ضبط قيمة منخفضة على جودة التعلم الآلي.",
|
||||
"image_preview_resolution": "معاينة الدقّة",
|
||||
"image_preview_resolution_description": "يُستخدم عند عرض صورة واحدة وللتعلم الآلي. ستحافظ الدقاتُ العالية على المزيد من التفاصيل ولكنها ستستغرق وقتًا أطول للترميز، ولها أحجام ملفات أكبر، ويمكن أن تقلل من استجابة التطبيق.",
|
||||
"image_preview_title": "إعدادات المعاينة",
|
||||
"image_quality": "الجودة",
|
||||
"image_quality_description": "جودة الصورة من 1-100. الأعلى هو الأفضل من حيث الجودة ولكنه ينتج ملفات أكبر، ويؤثر هذا الخيار على صور المعاينة والصور المصغرة.",
|
||||
"image_resolution": "الدقة",
|
||||
"image_resolution_description": "يمكن للدقة العالية الحفاظ على مزيد من التفاصيل ولكنها تستغرق وقتًا أطول للترميز، وتحتوي على أحجام ملفات أكبر ويمكن أن تقلل من استجابة التطبيق.",
|
||||
"image_settings": "إعدادات الصور",
|
||||
"image_settings_description": "إدارة جودة ودقة الصور التي تم إنشاؤها",
|
||||
"image_thumbnail_description": "صورة مصغرة صغيرة مع بيانات وصفية مجردة، تُستخدم عند عرض مجموعات من الصور مثل الجدول الزمني الرئيسي",
|
||||
"image_thumbnail_format": "تنسيق الصور المصغّرة",
|
||||
"image_thumbnail_quality_description": "تتراوح جودة الصورة المصغرة من 1 إلى 100. كلما كانت الجودة أعلى كان ذلك أفضل، ولكنها تنتج ملفات أكبر وقد تقلل من استجابة التطبيق.",
|
||||
"image_thumbnail_resolution": "دقة الصور المصغّرة",
|
||||
"image_thumbnail_resolution_description": "يُستخدم عند عرض مجموعات من الصور (المخطط الزمني الرئيسي، عرض الألبوم، وما إلى ذلك). ستحافظ الدقاتُ العالية على المزيد من التفاصيل ولكنها ستستغرق وقتًا أطول للترميز، ولها أحجام ملفات أكبر، ويمكن أن تقلل من استجابة التطبيق.",
|
||||
"image_thumbnail_title": "إعدادات الصورة المصغرة",
|
||||
"job_concurrency": "تزامن {job}",
|
||||
"job_created": "تم إنشاء الوظيفة",
|
||||
@@ -89,9 +88,6 @@
|
||||
"jobs_delayed": "{jobCount, plural, other {# مؤجلة}}",
|
||||
"jobs_failed": "{jobCount, plural, other {# فشلت}}",
|
||||
"library_created": "تم إنشاء المكتبة: {library}",
|
||||
"library_cron_expression": "تعبير Cron",
|
||||
"library_cron_expression_description": "\"اضبط فواصلَ زمنِ الفحص باستخدام صيغة cron. للمزيد من المعلومات، يرجى الرجوع إلى <link>Crontab Guru</link>\"",
|
||||
"library_cron_expression_presets": "إعدادات مسبقة لتعبير Cron",
|
||||
"library_deleted": "تم حذف المكتبة",
|
||||
"library_import_path_description": "حدد مجلدًا للاستيراد. سيتم فحص هذا المجلد، بما في ذلك المجلدات الفرعية، بحثًا عن الصور ومقاطع الفيديو.",
|
||||
"library_scanning": "الفحص الدوري",
|
||||
@@ -215,7 +211,6 @@
|
||||
"refreshing_all_libraries": "تحديث كافة المكتبات",
|
||||
"registration": "تسجيل المدير",
|
||||
"registration_description": "بما أنك أول مستخدم في النظام، سيتم تعيينك كمسؤول وستكون مسؤولًا عن المهام الإدارية، وسيتم إنشاء مستخدمين إضافيين بواسطتك.",
|
||||
"removing_deleted_files": "إزالة الملفات غير المتصلة",
|
||||
"repair_all": "إصلاح الكل",
|
||||
"repair_matched_items": "تمت مطابقة {count, plural, one {# عنصر} other {# عناصر}}",
|
||||
"repaired_items": "تم إصلاح {count, plural, one {# عنصر} other {# عناصر}}",
|
||||
@@ -223,8 +218,6 @@
|
||||
"reset_settings_to_default": "إعادة ضبط الإعدادات إلى الوضع الافتراضي",
|
||||
"reset_settings_to_recent_saved": "إعادة ضبط الإعدادات إلى الإعدادات المحفوظة مؤخرًا",
|
||||
"scanning_library": "مسح المكتبة",
|
||||
"scanning_library_for_changed_files": "فحص المكتبة لاكتشاف الملفات التي تم تغييرها",
|
||||
"scanning_library_for_new_files": "فحص المكتبة للبحث عن ملفات جديدة",
|
||||
"search_jobs": "البحث عن وظائف...",
|
||||
"send_welcome_email": "إرسال بريد ترحيبي",
|
||||
"server_external_domain_settings": "إسم النطاق الخارجي",
|
||||
@@ -261,7 +254,6 @@
|
||||
"these_files_matched_by_checksum": "تتم مطابقة هذه الملفات من خلال المجاميع الاختبارية الخاصة بهم",
|
||||
"thumbnail_generation_job": "إنشاء الصور المصغرة",
|
||||
"thumbnail_generation_job_description": "إنشاء صور مصغرة كبيرة وصغيرة وغير واضحة لكل أصل، بالإضافة إلى صور مصغرة لكل شخص",
|
||||
"transcode_policy_description": "",
|
||||
"transcoding_acceleration_api": "واجهة برمجة التطبيقات للتسريع",
|
||||
"transcoding_acceleration_api_description": "الواجهة البرمجية التي ستتفاعل مع جهازك لتسريع التحويل. هذا الإعداد هو \"أفضل محاولة\": سيعود إلى التحويل البرمجي في حالة الفشل. قد لا يعمل VP9 اعتمادًا على عتادك.",
|
||||
"transcoding_acceleration_nvenc": "NVENC (يتطلب GPU من NVIDIA)",
|
||||
@@ -313,8 +305,6 @@
|
||||
"transcoding_threads_description": "تؤدي القيم الأعلى إلى تشفير أسرع، ولكنها تترك مساحة أقل للخادم لمعالجة المهام الأخرى أثناء النشاط. يجب ألا تزيد هذه القيمة عن عدد مراكز وحدة المعالجة المركزية. يزيد من الإستغلال إذا تم ضبطه على 0.",
|
||||
"transcoding_tone_mapping": "رسم الخرائط النغمية",
|
||||
"transcoding_tone_mapping_description": "تحاول الحفاظ على مظهر مقاطع الفيديو HDR عند تحويلها إلى SDR. يقدم كل خوارزمية تنازلات مختلفة بين اللون والتفاصيل والسطوع. Hable تحافظ على التفاصيل، Mobius تحافظ على الألوان، و Reinhard تحافظ على السطوع.",
|
||||
"transcoding_tone_mapping_npl": "تحويل الصور من نطاق الإضاءة العالية",
|
||||
"transcoding_tone_mapping_npl_description": "سيتم ضبط الألوان لتبدو طبيعية على شاشة بهذه السطوع. على عكس المتوقع، تزيد القيم الأقل من سطوع الفيديو والعكس بسبب تعويضها لسطوع الشاشة. قيمة 0 تضبط هذه القيمة تلقائيًا.",
|
||||
"transcoding_transcode_policy": "سياسة الترميز",
|
||||
"transcoding_transcode_policy_description": "سياسة تحديد متى يجب ترميز الفيديو. سيتم دائمًا ترميز مقاطع الفيديو HDR (ما لم يتم تعطيل الترميز).",
|
||||
"transcoding_two_pass_encoding": "الترميز بمرورين",
|
||||
@@ -395,7 +385,6 @@
|
||||
"archive_or_unarchive_photo": "أرشفة الصورة أو إلغاء أرشفتها",
|
||||
"archive_size": "حجم الأرشيف",
|
||||
"archive_size_description": "تكوين حجم الأرشيف للتنزيلات (بالجيجابايت)",
|
||||
"archived": "",
|
||||
"archived_count": "{count, plural, other {الأرشيف #}}",
|
||||
"are_these_the_same_person": "هل هؤلاء هم نفس الشخص؟",
|
||||
"are_you_sure_to_do_this": "هل انت متأكد من أنك تريد أن تفعل هذا؟",
|
||||
@@ -445,10 +434,6 @@
|
||||
"cannot_merge_people": "لا يمكن دمج الأشخاص",
|
||||
"cannot_undo_this_action": "لا يمكنك التراجع عن هذا الإجراء!",
|
||||
"cannot_update_the_description": "لا يمكن تحديث الوصف",
|
||||
"cant_apply_changes": "",
|
||||
"cant_get_faces": "",
|
||||
"cant_search_people": "",
|
||||
"cant_search_places": "",
|
||||
"change_date": "غيّر التاريخ",
|
||||
"change_expiration_time": "تغيير وقت انتهاء الصلاحية",
|
||||
"change_location": "غيّر الموقع",
|
||||
@@ -562,13 +547,6 @@
|
||||
"duplicates": "التكرارات",
|
||||
"duplicates_description": "قم بحل كل مجموعة من خلال الإشارة إلى التكرارات، إن وجدت",
|
||||
"duration": "المدة",
|
||||
"durations": {
|
||||
"days": "",
|
||||
"hours": "",
|
||||
"minutes": "",
|
||||
"months": "",
|
||||
"years": ""
|
||||
},
|
||||
"edit": "تعديل",
|
||||
"edit_album": "تعديل الألبوم",
|
||||
"edit_avatar": "تعديل الصورة الشخصية",
|
||||
@@ -593,8 +571,6 @@
|
||||
"editor_crop_tool_h2_aspect_ratios": "نسب العرض إلى الارتفاع",
|
||||
"editor_crop_tool_h2_rotation": "التدوير",
|
||||
"email": "البريد الإلكتروني",
|
||||
"empty": "",
|
||||
"empty_album": "",
|
||||
"empty_trash": "أفرغ سلة المهملات",
|
||||
"empty_trash_confirmation": "هل أنت متأكد أنك تريد إفراغ سلة المهملات؟ سيؤدي هذا إلى إزالة جميع المحتويات الموجودة في سلة المهملات بشكل نهائي من Immich.\nلا يمكنك التراجع عن هذا الإجراء!",
|
||||
"enable": "تفعيل",
|
||||
@@ -655,8 +631,6 @@
|
||||
"unable_to_change_location": "غير قادر على تغيير الموقع",
|
||||
"unable_to_change_password": "غير قادر على تغيير كلمة المرور",
|
||||
"unable_to_change_visibility": "غير قادر على تغيير الظهور لـ {count, plural, one {# شخص} other {# أشخاص}}",
|
||||
"unable_to_check_item": "",
|
||||
"unable_to_check_items": "",
|
||||
"unable_to_complete_oauth_login": "غير قادر على إكمال تسجيل الدخول عبر OAuth",
|
||||
"unable_to_connect": "غير قادر على الإتصال",
|
||||
"unable_to_connect_to_server": "غير قادر على الإتصال بالسيرفر",
|
||||
@@ -697,12 +671,10 @@
|
||||
"unable_to_remove_album_users": "تعذر إزالة المستخدمين من الألبوم",
|
||||
"unable_to_remove_api_key": "تعذر إزالة مفتاح API",
|
||||
"unable_to_remove_assets_from_shared_link": "غير قادر على إزالة المحتويات من الرابط المشترك",
|
||||
"unable_to_remove_comment": "",
|
||||
"unable_to_remove_deleted_assets": "غير قادر على إزالة الملفات غير المتصلة",
|
||||
"unable_to_remove_library": "غير قادر على إزالة المكتبة",
|
||||
"unable_to_remove_partner": "غير قادر على إزالة الشريك",
|
||||
"unable_to_remove_reaction": "غير قادر على إزالة رد الفعل",
|
||||
"unable_to_remove_user": "",
|
||||
"unable_to_repair_items": "غير قادر على إصلاح العناصر",
|
||||
"unable_to_reset_password": "غير قادر على إعادة تعيين كلمة المرور",
|
||||
"unable_to_resolve_duplicate": "غير قادر على حل التكرارات",
|
||||
@@ -732,10 +704,6 @@
|
||||
"unable_to_update_user": "غير قادر على تحديث المستخدم",
|
||||
"unable_to_upload_file": "تعذر رفع الملف"
|
||||
},
|
||||
"every_day_at_onepm": "",
|
||||
"every_night_at_midnight": "",
|
||||
"every_night_at_twoam": "",
|
||||
"every_six_hours": "",
|
||||
"exif": "Exif (صيغة ملف صوري قابل للتبادل)",
|
||||
"exit_slideshow": "خروج من العرض التقديمي",
|
||||
"expand_all": "توسيع الكل",
|
||||
@@ -750,33 +718,27 @@
|
||||
"external": "خارجي",
|
||||
"external_libraries": "المكتبات الخارجية",
|
||||
"face_unassigned": "غير معين",
|
||||
"failed_to_get_people": "",
|
||||
"favorite": "مفضل",
|
||||
"favorite_or_unfavorite_photo": "تفضيل أو إلغاء تفضيل الصورة",
|
||||
"favorites": "المفضلة",
|
||||
"feature": "",
|
||||
"feature_photo_updated": "تم تحديث الصورة المميزة",
|
||||
"featurecollection": "",
|
||||
"features": "الميزات",
|
||||
"features_setting_description": "إدارة ميزات التطبيق",
|
||||
"file_name": "إسم الملف",
|
||||
"file_name_or_extension": "اسم الملف أو امتداده",
|
||||
"filename": "اسم الملف",
|
||||
"files": "",
|
||||
"filetype": "نوع الملف",
|
||||
"filter_people": "تصفية الاشخاص",
|
||||
"find_them_fast": "يمكنك العثور عليها بسرعة بالاسم من خلال البحث",
|
||||
"fix_incorrect_match": "إصلاح المطابقة غير الصحيحة",
|
||||
"folders": "المجلدات",
|
||||
"folders_feature_description": "تصفح عرض المجلد للصور ومقاطع الفيديو الموجودة على نظام الملفات",
|
||||
"force_re-scan_library_files": "فرض إعادة فحص جميع ملفات المكتبة",
|
||||
"forward": "إلى الأمام",
|
||||
"general": "عام",
|
||||
"get_help": "الحصول على المساعدة",
|
||||
"getting_started": "البدء",
|
||||
"go_back": "الرجوع للخلف",
|
||||
"go_to_search": "اذهب إلى البحث",
|
||||
"go_to_share_page": "انتقل إلى صفحة المشاركة",
|
||||
"group_albums_by": "تجميع الألبومات حسب...",
|
||||
"group_no": "بدون تجميع",
|
||||
"group_owner": "تجميع حسب المالك",
|
||||
@@ -802,10 +764,6 @@
|
||||
"image_alt_text_date_place_2_people": "{isVideo, select, true {Video} other {Image}} تم التقاطها في {city}، {country} مع {person1} و{person2} في {date}",
|
||||
"image_alt_text_date_place_3_people": "{isVideo, select, true {Video} other {Image}} تم التقاطها في {city}، {country} مع {person1}، {person2}، و{person3} في {date}",
|
||||
"image_alt_text_date_place_4_or_more_people": "{isVideo, select, true {Video} other {Image}} تم التقاطها في {city}, {country} with {person1}, {person2}, مع {additionalCount, number} آخرين في {date}",
|
||||
"image_alt_text_people": "{count, plural, =1 {مع {person1}} =2 {مع {person1} و {person2}} =3 {مع {person1} و {person2} و {person3}} other {مع {person1} و {person2} و {others, number} آخرين}}",
|
||||
"image_alt_text_place": "في {city}, {country}",
|
||||
"image_taken": "{isVideo, select, true {تم التقاط الفيديو} other {تم التقاط الصورة}}",
|
||||
"img": "",
|
||||
"immich_logo": "شعار immich",
|
||||
"immich_web_interface": "واجهة ويب immich",
|
||||
"import_from_json": "استيراد من JSON",
|
||||
@@ -826,7 +784,6 @@
|
||||
"invite_people": "دعوة الأشخاص",
|
||||
"invite_to_album": "دعوة إلى الألبوم",
|
||||
"items_count": "{count, plural, one {# عنصر} other {# عناصر}}",
|
||||
"job_settings_description": "",
|
||||
"jobs": "الوظائف",
|
||||
"keep": "احتفظ",
|
||||
"keep_all": "احتفظ بالكل",
|
||||
@@ -841,31 +798,6 @@
|
||||
"level": "المستوى",
|
||||
"library": "مكتبة",
|
||||
"library_options": "خيارات المكتبة",
|
||||
"license_account_info": "حسابك مرخص",
|
||||
"license_activated_subtitle": "شكرا بدعمك لـ Immich وبرمجيات المصدر المفتوح",
|
||||
"license_activated_title": "رخصتك نُشطت بنجاح",
|
||||
"license_button_activate": "تنشيط",
|
||||
"license_button_buy": "شراء",
|
||||
"license_button_buy_license": "اشتر رخصة",
|
||||
"license_button_select": "إختر",
|
||||
"license_failed_activation": "فشل في تفعيل الترخيص. يرجى التحقق من بريدك الإلكتروني للحصول على مفتاح الترخيص الصحيح!",
|
||||
"license_individual_description_1": "رخصة واحدة لكل مستخدم على أي خادم",
|
||||
"license_individual_title": "رخصة فردية",
|
||||
"license_info_licensed": "مُرَخص",
|
||||
"license_info_unlicensed": "غير مُرَخص",
|
||||
"license_input_suggestion": "لديك رخصة؟ أدخِل الرمز بالأسفل",
|
||||
"license_license_subtitle": "اشتر رخصةً لدعم Immich",
|
||||
"license_license_title": "الرخصة",
|
||||
"license_lifetime_description": "رخصة مدى الحياة",
|
||||
"license_per_server": "لكل خادم",
|
||||
"license_per_user": "لكل مستحدم",
|
||||
"license_server_description_1": "رخصة واحدة لكل خادم",
|
||||
"license_server_description_2": "رخصة لكل المستخدمين على الخادم",
|
||||
"license_server_title": "رخصة خادم",
|
||||
"license_trial_info_1": "أنت تستخدم نسخةً غير مرخصة ل Immich",
|
||||
"license_trial_info_2": "لقد استخدمتَ Immich تقريبا لمدة",
|
||||
"license_trial_info_3": "{accountAge, plural, one {# يوم} other {# أيام}}",
|
||||
"license_trial_info_4": "يُرجى التفكير في شراء رخصة لدعم التطوير المستمر للخدمة",
|
||||
"light": "المضيئ",
|
||||
"like_deleted": "تم حذف الإعجاب",
|
||||
"link_motion_video": "رابط فيديو الحركة",
|
||||
@@ -887,6 +819,7 @@
|
||||
"look": "الشكل",
|
||||
"loop_videos": "تكرار مقاطع الفيديو",
|
||||
"loop_videos_description": "فَعْل لتكرار مقطع فيديو تلقائيًا في عارض التفاصيل.",
|
||||
"main_branch_warning": "أنت تستخدم إصداراً تطويرياً؛ ونحن نوصي بشدة باستخدام إصدار النشر!",
|
||||
"make": "صنع",
|
||||
"manage_shared_links": "إدارة الروابط المشتركة",
|
||||
"manage_sharing_with_partners": "إدارة المشاركة مع الشركاء",
|
||||
@@ -969,7 +902,6 @@
|
||||
"onboarding_welcome_user": "مرحبا، {user}",
|
||||
"online": "متصل",
|
||||
"only_favorites": "المفضلة فقط",
|
||||
"only_refreshes_modified_files": "تحديث الملفات المعدلة فقط",
|
||||
"open_in_map_view": "فتح في عرض الخريطة",
|
||||
"open_in_openstreetmap": "فتح في OpenStreetMap",
|
||||
"open_the_search_filters": "افتح مرشحات البحث",
|
||||
@@ -1007,7 +939,6 @@
|
||||
"people_edits_count": "تم تعديل {count, plural, one {# شخص } other {# أشخاص }}",
|
||||
"people_feature_description": "تصفح الصور ومقاطع الفيديو المجمعة حسب الأشخاص",
|
||||
"people_sidebar_description": "عرض رابط للأشخاص في الشريط الجانبي",
|
||||
"perform_library_tasks": "",
|
||||
"permanent_deletion_warning": "تحذير الحذف الدائم",
|
||||
"permanent_deletion_warning_setting_description": "إظهار تحذير عند حذف المحتويات نهائيًا",
|
||||
"permanently_delete": "حذف بشكل دائم",
|
||||
@@ -1029,7 +960,6 @@
|
||||
"play_memories": "تشغيل الذكريات",
|
||||
"play_motion_photo": "تشغيل الصور المتحركة",
|
||||
"play_or_pause_video": "تشغيل الفيديو أو إيقافه مؤقتًا",
|
||||
"point": "",
|
||||
"port": "المنفذ",
|
||||
"preset": "الإعداد المسبق",
|
||||
"preview": "معاينة",
|
||||
@@ -1074,12 +1004,10 @@
|
||||
"purchase_server_description_2": "حالة الداعم",
|
||||
"purchase_server_title": "الخادم",
|
||||
"purchase_settings_server_activated": "يتم إدارة مفتاح منتج الخادم من قبل مدير النظام",
|
||||
"range": "",
|
||||
"rating": "تقييم نجمي",
|
||||
"rating_clear": "مسح التقييم",
|
||||
"rating_count": "{count, plural, one {# نجمة} other {# نجوم}}",
|
||||
"rating_description": "اعرض تقييم EXIF في لوحة المعلومات",
|
||||
"raw": "",
|
||||
"reaction_options": "خيارات رد الفعل",
|
||||
"read_changelog": "قراءة سجل التغيير",
|
||||
"reassign": "إعادة التعيين",
|
||||
@@ -1090,11 +1018,13 @@
|
||||
"recent_searches": "عمليات البحث الأخيرة",
|
||||
"refresh": "تحديث",
|
||||
"refresh_encoded_videos": "تحديث مقاطع الفيديو المشفرة",
|
||||
"refresh_faces": "تحديث الوجوه",
|
||||
"refresh_metadata": "تحديث البيانات الوصفية",
|
||||
"refresh_thumbnails": "تحديث الصور المصغرة",
|
||||
"refreshed": "تم التحديث",
|
||||
"refreshes_every_file": "إعادة قراءة كافة الملفات الموجودة والجديدة",
|
||||
"refreshing_encoded_video": "جارٍ تحديث الفيديو المرمز",
|
||||
"refreshing_faces": "جاري تحديث الوجوه",
|
||||
"refreshing_metadata": "جارٍ تحديث البيانات الوصفية",
|
||||
"regenerating_thumbnails": "جارٍ تجديد الصور المصغرة",
|
||||
"remove": "إزالة",
|
||||
@@ -1122,7 +1052,6 @@
|
||||
"reset": "إعادة ضبط",
|
||||
"reset_password": "إعادة تعيين كلمة المرور",
|
||||
"reset_people_visibility": "إعادة ضبط ظهور الأشخاص",
|
||||
"reset_settings_to_default": "",
|
||||
"reset_to_default": "إعادة التعيين إلى الافتراضي",
|
||||
"resolve_duplicates": "معالجة النسخ المكررة",
|
||||
"resolved_all_duplicates": "تم حل جميع التكرارات",
|
||||
@@ -1142,9 +1071,7 @@
|
||||
"saved_settings": "تم حفظ الإعدادات",
|
||||
"say_something": "قل شيئًا",
|
||||
"scan_all_libraries": "فحص كل المكتبات",
|
||||
"scan_all_library_files": "إعادة فحص كافة ملفات المكتبة",
|
||||
"scan_library": "مسح",
|
||||
"scan_new_library_files": "فحص ملفات المكتبة الجديدة",
|
||||
"scan_settings": "إعدادات الفحص",
|
||||
"scanning_for_album": "جارٍ الفحص عن ألبوم...",
|
||||
"search": "بحث",
|
||||
@@ -1187,7 +1114,6 @@
|
||||
"selected_count": "{count, plural, other {# محددة }}",
|
||||
"send_message": "أرسل رسالة",
|
||||
"send_welcome_email": "أرسل بريدًا إلكترونيًا ترحيبيًا",
|
||||
"server": "الخادم",
|
||||
"server_offline": "الخادم غير متصل",
|
||||
"server_online": "الخادم متصل",
|
||||
"server_stats": "إحصائيات الخادم",
|
||||
@@ -1301,7 +1227,6 @@
|
||||
"to_trash": "حذف",
|
||||
"toggle_settings": "الإعدادات",
|
||||
"toggle_theme": "تبديل المظهر الداكن",
|
||||
"toggle_visibility": "تبديل الرؤية",
|
||||
"total_usage": "الاستخدام الإجمالي",
|
||||
"trash": "المهملات",
|
||||
"trash_all": "نقل الكل إلى سلة المهملات",
|
||||
@@ -1311,12 +1236,10 @@
|
||||
"trashed_items_will_be_permanently_deleted_after": "سيتم حذفُ العناصر المحذوفة نِهائيًا بعد {days, plural, one {# يوم} other {# أيام }}.",
|
||||
"type": "النوع",
|
||||
"unarchive": "أخرج من الأرشيف",
|
||||
"unarchived": "",
|
||||
"unarchived_count": "{count, plural, other {غير مؤرشفة #}}",
|
||||
"unfavorite": "أزل التفضيل",
|
||||
"unhide_person": "أظهر الشخص",
|
||||
"unknown": "غير معروف",
|
||||
"unknown_album": "",
|
||||
"unknown_year": "سنة غير معروفة",
|
||||
"unlimited": "غير محدود",
|
||||
"unlink_motion_video": "إلغاء ربط فيديو الحركة",
|
||||
@@ -1348,8 +1271,6 @@
|
||||
"use_custom_date_range": "استخدم النطاق الزمني المخصص بدلاً من ذلك",
|
||||
"user": "مستخدم",
|
||||
"user_id": "معرف المستخدم",
|
||||
"user_license_settings": "رخصة",
|
||||
"user_license_settings_description": "ادر رخصتك",
|
||||
"user_liked": "قام {user} بالإعجاب {type, select, photo {بهذه الصورة} video {بهذا الفيديو} asset {بهذا المحتوى} other {بها}}",
|
||||
"user_purchase_settings": "الشراء",
|
||||
"user_purchase_settings_description": "إدارة عملية الشراء الخاصة بك",
|
||||
@@ -1363,6 +1284,8 @@
|
||||
"version": "الإصدار",
|
||||
"version_announcement_closing": "صديقك، أليكس",
|
||||
"version_announcement_message": "مرحباً يا صديقي، هنالك نسخة جديدة من التطبيق. خذ وقتك لزيارة <link>ملاحظات الإصدار</link> والتأكد من أن ملف <code>docker-compose.yml</code> وإعداد <code>.env</code> مُحدّثين لتجنب أي إعدادات خاطئة، خاصةً إذا كنت تستخدم WatchTower أو أي آلية تقوم بتحديث التطبيق تلقائياً.",
|
||||
"version_history": "تاريخ الإصدار",
|
||||
"version_history_item": "تم تثبيت {version} في {date}",
|
||||
"video": "فيديو",
|
||||
"video_hover_setting": "تشغيل الصورة المصغرة للفيديو عند التمرير",
|
||||
"video_hover_setting_description": "تشغيل الصورة المصغرة للفيديو عند تحريك الماوس فوق العنصر. حتى عند التعطيل، يمكن بدء التشغيل عن طريق التمرير فوق رمز التشغيل.",
|
||||
@@ -1377,7 +1300,6 @@
|
||||
"view_next_asset": "عرض المحتوى التالي",
|
||||
"view_previous_asset": "عرض المحتوى السابق",
|
||||
"view_stack": "عرض التكديس",
|
||||
"viewer": "",
|
||||
"visibility_changed": "الرؤية تغيرت لـ {count, plural, one {شخص واحد} other {# عدة أشخاص}}",
|
||||
"waiting": "في الانتظار",
|
||||
"warning": "تحذير",
|
||||
@@ -45,6 +45,39 @@
|
||||
"image_settings": "Şəklin parametrləri",
|
||||
"image_settings_description": "Hazırlanan şəkillərin keyfiyyətini və çözümlülüyünü idarə et",
|
||||
"image_thumbnail_title": "Önizləmə parametrləri",
|
||||
"job_concurrency": "{job}paralellik"
|
||||
"job_concurrency": "{job}paralellik",
|
||||
"job_created": "Tapşırıq yaradıldı",
|
||||
"job_not_concurrency_safe": "Bu tapşırıq parallel fəaliyyət üçün uyğun deyil",
|
||||
"job_settings": "Tapşırıq parametrləri",
|
||||
"job_settings_description": "Parallel şəkildə fəaliyyət göstərən tapşırıqları idarə et",
|
||||
"job_status": "Tapşırıq statusu",
|
||||
"jobs_delayed": "{jobCount, plural, other {# gecikməli}}",
|
||||
"jobs_failed": "{jobCount, plural, other {# uğursuz}}",
|
||||
"library_created": "{library} kitabxanası yaradıldı",
|
||||
"library_deleted": "Kitabxana silindi",
|
||||
"library_import_path_description": "İdxal olunacaq qovluöu seçin. Bu qovluq, alt qovluqlar daxil olmaqla şəkil və videolar üçün skan ediləcəkdir.",
|
||||
"library_scanning": "Periodik skan",
|
||||
"library_scanning_description": "Periodik kitabxana skanını confiqurasiya et",
|
||||
"library_scanning_enable_description": "Periodik kitabxana skanını aktivləşdir",
|
||||
"library_settings": "Xarici kitabxana",
|
||||
"library_settings_description": "Xarici kitabxana parametrlərini idarə et",
|
||||
"library_tasks_description": "Kitabxana tapşırıqlarını yerinə yetir",
|
||||
"library_watching_enable_description": "Fayl dəyişiklikləri üçün xarici kitabxanalara baxış keçirin",
|
||||
"library_watching_settings": "Kitabxana nəzarəti (EKSPERİMENTAL)",
|
||||
"library_watching_settings_description": "Dəyişdirilən faylları avtomatik olaraq yoxla",
|
||||
"logging_enable_description": "Jurnalı aktivləşdir",
|
||||
"logging_level_description": "Aktiv edildikdə hansı jurnal səviyyəsi istifadə olunur.",
|
||||
"logging_settings": "",
|
||||
"machine_learning_clip_model": "CLIP modeli",
|
||||
"machine_learning_clip_model_description": "<link>Burada</link>qeyd olunan CLIP modelinin adı. Modeli dəyişdirdikdən sonra bütün şəkillər üçün 'Ağıllı Axtarış' funksiyasını yenidən işə salmalısınız.",
|
||||
"machine_learning_duplicate_detection": "Dublikat Aşkarlama",
|
||||
"machine_learning_duplicate_detection_enabled": "Dublikat aşkarlamanı aktiv etmək",
|
||||
"machine_learning_duplicate_detection_enabled_description": "Əgər deaktiv edilibsə, birə-bir eyni fayllar yenədə silinəcək.",
|
||||
"machine_learning_duplicate_detection_setting_description": "Bir-birinin dublikatı olan faylları tapmaq üçün CLIP-dən istifadə edin",
|
||||
"machine_learning_enabled": "Maşın öyrənməsini aktiv edin",
|
||||
"machine_learning_enabled_description": "Əgər deaktiv edilərsə, aşağıdakı parametrlərdən asılı olmayaq, bütün Maşın Öyrənmə funksiyaları deaktiv ediləcək.",
|
||||
"machine_learning_facial_recognition": "Üz Tanıma",
|
||||
"machine_learning_facial_recognition_description": "Şəkillərdəki üzləri aşkarla, tanı və qruplaşdır",
|
||||
"machine_learning_facial_recognition_model": "Üz tanıma modeli"
|
||||
}
|
||||
}
|
||||
32
i18n/be.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"about": "Пра праграму",
|
||||
"account": "Уліковы запіс",
|
||||
"account_settings": "Налады акаўнта",
|
||||
"acknowledge": "Пацвердзіць",
|
||||
"action": "Дзеянне",
|
||||
"actions": "Дзеянні",
|
||||
"active": "Актыўны",
|
||||
"activity": "Актыўнасць",
|
||||
"activity_changed": "Актыўнасць {enabled, select, true {уключана} other {адключана}}",
|
||||
"add": "Дадаць",
|
||||
"add_a_description": "Дадаць апісанне",
|
||||
"add_a_location": "Дадаць месца",
|
||||
"add_a_name": "Дадаць імя",
|
||||
"add_a_title": "Дадаць загаловак",
|
||||
"add_exclusion_pattern": "Дадаць шаблон выключэння",
|
||||
"add_import_path": "Дадаць шлях імпарту",
|
||||
"add_location": "Дадайце месца",
|
||||
"add_more_users": "Дадаць больш карыстальнікаў",
|
||||
"add_partner": "Дадаць партнёра",
|
||||
"add_path": "Дадаць шлях",
|
||||
"add_photos": "Дадаць фота",
|
||||
"add_to": "Дадаць у...",
|
||||
"add_to_album": "Дадаць у альбом",
|
||||
"add_to_shared_album": "Дадаць у агульны альбом",
|
||||
"added_to_archive": "Дададзена ў архіў",
|
||||
"added_to_favorites": "Дададзена ў абраныя",
|
||||
"added_to_favorites_count": "Дададзена {count, number} да абранага",
|
||||
"admin": {
|
||||
"add_exclusion_pattern_description": "Дадайце шаблоны выключэнняў. Падтрымліваецца выкарыстанне сімвалаў * , ** і ?. Каб ігнараваць усе файлы ў любой дырэкторыі з назвай \"Raw\", выкарыстоўвайце \"**/Raw/**\". Каб ігнараваць усе файлы, якія заканчваюцца на \".tif\", выкарыстоўвайце \"**/.tif\". Каб ігнараваць абсолютны шлях, выкарыстоўвайце \"/path/to/ignore/**\"."
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,7 @@
|
||||
"authentication_settings_disable_all": "Сигурни ли сте, че искате да деактивирате всички методи за вписване? Вписването ще бъде напълно деактивирано.",
|
||||
"authentication_settings_reenable": "За да реактивирате, изполвайте <link>Server Command</link>.",
|
||||
"background_task_job": "Процеси на заден фон",
|
||||
"backup_database": "Резервна База данни",
|
||||
"check_all": "Провери всичко",
|
||||
"cleared_jobs": "Изчистени задачи от тип: {job}",
|
||||
"config_set_by_file": "Конфигурацията е зададена от файл",
|
||||
@@ -59,16 +60,9 @@
|
||||
"image_prefer_embedded_preview_setting_description": "Използване на вградените прегледи в RAW снимките като вход за обработка на изображенията, когато има такива. Това може да доведе до по-точни цветове за някои изображения, но качеството на прегледите зависи от камерата и изображението може да има повече компресионни артефакти.",
|
||||
"image_prefer_wide_gamut": "Предпочитане на широка гама",
|
||||
"image_prefer_wide_gamut_setting_description": "Използване на Display P3 за миниатюри. Това запазва по-добре жизнеността на изображенията с широки цветови пространства, но изображенията може да изглеждат по различен начин на стари устройства със стара версия на браузъра. sRGB изображенията се запазват като sRGB, за да се избегнат цветови промени.",
|
||||
"image_preview_format": "Формат на прегледите",
|
||||
"image_preview_resolution": "Резолюция на прегледите",
|
||||
"image_preview_resolution_description": "Използва се при разглеждане на единична снимка и за машинно обучение. По-високите резолюции могат да запазят повече детайли, но отнемат повече време за кодиране, имат по-големи размери на файловете и могат да намалят отзивчивостта на приложението.",
|
||||
"image_quality": "Качество",
|
||||
"image_quality_description": "Качество на изображението от 1-100. По-голяма стойност води до по-добро качество, но създава по-големи файлове. Тази настройка засяга изображенията от тип преглед и миниатюра.",
|
||||
"image_settings": "Настройки за изображенията",
|
||||
"image_settings_description": "Управляване качеството и резолюцията на създадените изображения",
|
||||
"image_thumbnail_format": "Формат на миниатюрните изображения",
|
||||
"image_thumbnail_resolution": "Резолюция на миниатюрните изображения",
|
||||
"image_thumbnail_resolution_description": "Използва се при разглеждане на групи от снимки (основна времева линия, изглед на албум и др.). По-високите резолюции могат да запазят повече детайли, но отнемат повече време за кодиране, имат по-големи размери на файловете и могат да намалят отзивчивостта на приложението.",
|
||||
"job_concurrency": "Паралелност на {job}",
|
||||
"job_created": "Задачата е създадена",
|
||||
"job_not_concurrency_safe": "Тази задача не е безопасна за паралелно изпълнение.",
|
||||
@@ -78,9 +72,6 @@
|
||||
"jobs_delayed": "{jobCount, plural, other {# delayed}}",
|
||||
"jobs_failed": "{jobCount, plural, other {# failed}}",
|
||||
"library_created": "Създадена библиотека: {library}",
|
||||
"library_cron_expression": "Cron израз",
|
||||
"library_cron_expression_description": "Задайте интервала за сканиране чрез cron интервал. За повече информация, вижте например <link>Crontab Guru</link>",
|
||||
"library_cron_expression_presets": "Предварителни настройки на Cron израза",
|
||||
"library_deleted": "Библиотека е изтрита",
|
||||
"library_import_path_description": "Посочете папка за импортиране. Тази папка, включително подпапките, ще бъдат сканирани за изображения и видеоклипове.",
|
||||
"library_scanning": "Периодично сканиране",
|
||||
@@ -203,7 +194,6 @@
|
||||
"refreshing_all_libraries": "Опресняване на всички библиотеки",
|
||||
"registration": "Администраторска регистрация",
|
||||
"registration_description": "Тъй като сте първият потребител в системата, ще бъдете назначен като администратор и ще отговаряте за административните задачи, а допълнителните потребители ще бъдат създадени от вас.",
|
||||
"removing_deleted_files": "Премахване на офлайн файлове",
|
||||
"repair_all": "Поправяне на всичко",
|
||||
"repair_matched_items": "{count, plural, one {Съвпадащ елемент (#)} other {Съвпадащи елементи (#)}}",
|
||||
"repaired_items": "{count, plural, one {Поправен елемент (#)} other {Поправени елементи (#)}}",
|
||||
@@ -211,8 +201,6 @@
|
||||
"reset_settings_to_default": "Възстановяване на настройките по подразбиране",
|
||||
"reset_settings_to_recent_saved": "Възстановяване на настройките до последните запазени настройки",
|
||||
"scanning_library": "Сканиране на библиотеката",
|
||||
"scanning_library_for_changed_files": "Сканиране на библиотеката за променени файлове",
|
||||
"scanning_library_for_new_files": "Сканиране на библиотеката за нови файлове",
|
||||
"search_jobs": "Търсене на задачи...",
|
||||
"send_welcome_email": "Изпращане на имейл за добре дошли",
|
||||
"server_external_domain_settings": "Външен домейн",
|
||||
@@ -299,8 +287,6 @@
|
||||
"transcoding_threads_description": "По-високите стойности водят до по-бързо разкодиране, но оставят по-малко място за сървъра да обработва други задачи, докато е активен. Тази стойност не трябва да надвишава броя на процесорните ядра. Увеличава максимално използването, ако е зададено на 0.",
|
||||
"transcoding_tone_mapping": "",
|
||||
"transcoding_tone_mapping_description": "Опитва се да запази външния вид на HDR видеоклипове, когато се преобразува в SDR. Всеки алгоритъм прави различни компромиси за цвят, детайлност и яркост. Hable запазва детайлите, Mobius запазва цвета, а Reinhard запазва яркостта.",
|
||||
"transcoding_tone_mapping_npl": "",
|
||||
"transcoding_tone_mapping_npl_description": "Цветовете ще бъдат коригирани, за да изглеждат нормално за дисплей с тази яркост. Противоинтуитивно, по-ниските стойности увеличават яркостта на видеото и обратно, тъй като компенсират яркостта на дисплея. 0 задава тази стойност автоматично.",
|
||||
"transcoding_transcode_policy": "Правила за транскодиране",
|
||||
"transcoding_transcode_policy_description": "Правила за това кога видеоклипът трябва да бъде транскодиран. HDR видеоклиповете винаги ще бъдат транскодирани (освен ако транскодирането е деактивирано).",
|
||||
"transcoding_two_pass_encoding": "Кодиране с двойно минаване",
|
||||
@@ -376,14 +362,12 @@
|
||||
"archive_or_unarchive_photo": "Архивиране или деархивиране на снимка",
|
||||
"archive_size": "Размер на архива",
|
||||
"archive_size_description": "Конфигурирайте размера на архива за изтегляния (в GiB)",
|
||||
"archived": "",
|
||||
"are_these_the_same_person": "Това едно и също лице ли е?",
|
||||
"asset_offline": "Ресурсът е офлайн",
|
||||
"asset_skipped": "Пропуснато",
|
||||
"asset_uploaded": "Качено",
|
||||
"asset_uploading": "Качване...",
|
||||
"assets": "Ресурси",
|
||||
"assets_moved_to_trash": "",
|
||||
"authorized_devices": "Удостоверени устройства",
|
||||
"back": "Назад",
|
||||
"back_close_deselect": "Назад, затваряне или премахване на избора",
|
||||
@@ -403,10 +387,6 @@
|
||||
"cannot_merge_people": "Не може да обединява хора",
|
||||
"cannot_undo_this_action": "Не можете да отмените това действие!",
|
||||
"cannot_update_the_description": "Описанието не може да бъде актуализирано",
|
||||
"cant_apply_changes": "",
|
||||
"cant_get_faces": "",
|
||||
"cant_search_people": "",
|
||||
"cant_search_places": "",
|
||||
"change_date": "Промени датата",
|
||||
"change_expiration_time": "Променете времето на изтичане",
|
||||
"change_location": "Промени локацията",
|
||||
@@ -650,7 +630,6 @@
|
||||
"external": "Външно",
|
||||
"external_libraries": "Външни библиотеки",
|
||||
"face_unassigned": "Незададено",
|
||||
"failed_to_get_people": "",
|
||||
"favorite": "Любим",
|
||||
"favorite_or_unfavorite_photo": "",
|
||||
"favorites": "Любими",
|
||||
@@ -662,14 +641,12 @@
|
||||
"filter_people": "Филтриране на хора",
|
||||
"find_them_fast": "Намерете ги бързо по име с търсене",
|
||||
"fix_incorrect_match": "Поправяне на неправилно съвпадение",
|
||||
"force_re-scan_library_files": "Принудително повторно сканиране на всички библиотечни файлове",
|
||||
"forward": "Напред",
|
||||
"general": "Общи",
|
||||
"get_help": "Помощ",
|
||||
"getting_started": "",
|
||||
"go_back": "Връщане назад",
|
||||
"go_to_search": "Преминаване към търсене",
|
||||
"go_to_share_page": "",
|
||||
"group_albums_by": "Групирай албум по...",
|
||||
"group_owner": "Групиране по собственик",
|
||||
"group_year": "Групиране по година",
|
||||
@@ -685,7 +662,6 @@
|
||||
"hour": "Час",
|
||||
"image": "Изображение",
|
||||
"image_alt_text_date": "на {date}",
|
||||
"image_alt_text_place": "в {city}, {country}",
|
||||
"immich_logo": "Immich лого",
|
||||
"immich_web_interface": "",
|
||||
"import_from_json": "Импортиране от JSON",
|
||||
@@ -718,29 +694,6 @@
|
||||
"level": "Ниво",
|
||||
"library": "Библиотека",
|
||||
"library_options": "Опции на библиотеката",
|
||||
"license_account_info": "Вашият акаунт е лицензиран",
|
||||
"license_activated_title": "Вашият лиценз е активиран успешно",
|
||||
"license_button_activate": "Активирай",
|
||||
"license_button_buy": "Купи",
|
||||
"license_button_buy_license": "Купи лиценз",
|
||||
"license_button_select": "Избери",
|
||||
"license_failed_activation": "Неуспешно активиране на лиценз. Моля, проверете имейла си за правилния лицензен ключ!",
|
||||
"license_individual_description_1": "1 лиценз за потребител на всеки сървър",
|
||||
"license_individual_title": "Индивидуален лиценз",
|
||||
"license_info_licensed": "Лицензиран",
|
||||
"license_info_unlicensed": "Не лицензиран",
|
||||
"license_input_suggestion": "Имате лиценз? Въведете ключа по-долу",
|
||||
"license_license_subtitle": "Купете лиценз, за да подкрепите Immich",
|
||||
"license_license_title": "ЛИЦЕНЗ",
|
||||
"license_lifetime_description": "Доживотен лиценз",
|
||||
"license_per_server": "За сървър",
|
||||
"license_per_user": "За потребител",
|
||||
"license_server_description_1": "1 лиценз за сървър",
|
||||
"license_server_description_2": "Лиценз за всички потребители на сървъра",
|
||||
"license_server_title": "Лиценз за сървър",
|
||||
"license_trial_info_1": "Работите с нелицензирана версия на Immich",
|
||||
"license_trial_info_2": "Използвали сте Immich за приблизително",
|
||||
"license_trial_info_4": "Моля, помислете за закупуване на лиценз, за да подкрепите по-нататъшното развитие на услугата",
|
||||
"light": "Светло",
|
||||
"link_options": "Опции на линк за споделяне",
|
||||
"link_to_oauth": "",
|
||||
@@ -832,7 +785,6 @@
|
||||
"onboarding_welcome_user": "Добре дошъл, {user}",
|
||||
"online": "Онлайн",
|
||||
"only_favorites": "Само любими",
|
||||
"only_refreshes_modified_files": "Опреснява само модифицирани файлове",
|
||||
"open_the_search_filters": "Отваряне на филтрите за търсене",
|
||||
"options": "Настройки",
|
||||
"or": "или",
|
||||
@@ -870,7 +822,6 @@
|
||||
"permanent_deletion_warning_setting_description": "Показване на предупреждение при трайно изтриване на активи",
|
||||
"permanently_delete": "Трайно изтриване",
|
||||
"permanently_deleted_asset": "",
|
||||
"permanently_deleted_assets": "",
|
||||
"person": "Човек",
|
||||
"photos": "Снимки",
|
||||
"photos_count": "",
|
||||
@@ -931,8 +882,6 @@
|
||||
"saved_settings": "",
|
||||
"say_something": "",
|
||||
"scan_all_libraries": "",
|
||||
"scan_all_library_files": "",
|
||||
"scan_new_library_files": "",
|
||||
"scan_settings": "",
|
||||
"scanning_for_album": "",
|
||||
"search": "Търсене",
|
||||
@@ -967,7 +916,6 @@
|
||||
"selected": "Избрано",
|
||||
"send_message": "Изпратете съобщение",
|
||||
"send_welcome_email": "Изпратете имейл за добре дошли",
|
||||
"server": "Сървър",
|
||||
"server_offline": "Сървър офлайн",
|
||||
"server_online": "Сървър онлайн",
|
||||
"server_stats": "Статус на сървъра",
|
||||
@@ -1070,7 +1018,6 @@
|
||||
"to_trash": "Кошче",
|
||||
"toggle_settings": "Превключване на настройките",
|
||||
"toggle_theme": "Превключване на тема",
|
||||
"toggle_visibility": "",
|
||||
"total_usage": "Общо използвано",
|
||||
"trash": "кошче",
|
||||
"trash_all": "Изхвърли всички",
|
||||
@@ -1079,7 +1026,6 @@
|
||||
"trashed_items_will_be_permanently_deleted_after": "Изхвърлените в кошчето елементи ще бъдат изтрити за постоянно след {days, plural, one {# day} other {# days}}.",
|
||||
"type": "Тип",
|
||||
"unarchive": "Разархивирай",
|
||||
"unarchived": "",
|
||||
"unfavorite": "Премахване от любимите",
|
||||
"unhide_person": "",
|
||||
"unknown": "Неизвестно",
|
||||
@@ -1135,13 +1081,12 @@
|
||||
"view_next_asset": "Преглед на следващия файл",
|
||||
"view_previous_asset": "Преглед на предишния файл",
|
||||
"view_stack": "Покажи в стек",
|
||||
"viewer": "",
|
||||
"visibility_changed": "Видимостта е променена за {count, plural, one {# person} other {# people}}",
|
||||
"waiting": "в изчакване",
|
||||
"warning": "Внимание",
|
||||
"week": "Седмица",
|
||||
"welcome": "Добре дошли",
|
||||
"welcome_to_immich": "Добре дошли в immich",
|
||||
"welcome_to_immich": "Добре дошли в Immich",
|
||||
"year": "Година",
|
||||
"yes": "Да",
|
||||
"you_dont_have_any_shared_links": "Нямате споделени връзки",
|
||||
@@ -33,7 +33,6 @@
|
||||
"confirm_email_below": "",
|
||||
"confirm_reprocess_all_faces": "",
|
||||
"confirm_user_password_reset": "",
|
||||
"crontab_guru": "",
|
||||
"disable_login": "",
|
||||
"duplicate_detection_job_description": "",
|
||||
"exclusion_pattern_description": "",
|
||||
@@ -49,16 +48,9 @@
|
||||
"image_prefer_embedded_preview_setting_description": "",
|
||||
"image_prefer_wide_gamut": "",
|
||||
"image_prefer_wide_gamut_setting_description": "",
|
||||
"image_preview_format": "",
|
||||
"image_preview_resolution": "",
|
||||
"image_preview_resolution_description": "",
|
||||
"image_quality": "",
|
||||
"image_quality_description": "",
|
||||
"image_settings": "",
|
||||
"image_settings_description": "",
|
||||
"image_thumbnail_format": "",
|
||||
"image_thumbnail_resolution": "",
|
||||
"image_thumbnail_resolution_description": "",
|
||||
"job_concurrency": "",
|
||||
"job_not_concurrency_safe": "",
|
||||
"job_settings": "",
|
||||
@@ -67,8 +59,6 @@
|
||||
"jobs_delayed": "",
|
||||
"jobs_failed": "",
|
||||
"library_created": "",
|
||||
"library_cron_expression": "",
|
||||
"library_cron_expression_presets": "",
|
||||
"library_deleted": "",
|
||||
"library_import_path_description": "",
|
||||
"library_scanning": "",
|
||||
@@ -172,15 +162,12 @@
|
||||
"paths_validated_successfully": "",
|
||||
"quota_size_gib": "",
|
||||
"refreshing_all_libraries": "",
|
||||
"removing_deleted_files": "",
|
||||
"repair_all": "",
|
||||
"repair_matched_items": "",
|
||||
"repaired_items": "",
|
||||
"require_password_change_on_login": "",
|
||||
"reset_settings_to_default": "",
|
||||
"reset_settings_to_recent_saved": "",
|
||||
"scanning_library_for_changed_files": "",
|
||||
"scanning_library_for_new_files": "",
|
||||
"send_welcome_email": "",
|
||||
"server_external_domain_settings": "",
|
||||
"server_external_domain_settings_description": "",
|
||||
@@ -255,8 +242,6 @@
|
||||
"transcoding_threads_description": "",
|
||||
"transcoding_tone_mapping": "",
|
||||
"transcoding_tone_mapping_description": "",
|
||||
"transcoding_tone_mapping_npl": "",
|
||||
"transcoding_tone_mapping_npl_description": "",
|
||||
"transcoding_transcode_policy": "",
|
||||
"transcoding_transcode_policy_description": "",
|
||||
"transcoding_two_pass_encoding": "",
|
||||
@@ -308,7 +293,6 @@
|
||||
"appears_in": "",
|
||||
"archive": "",
|
||||
"archive_or_unarchive_photo": "",
|
||||
"archived": "",
|
||||
"asset_offline": "",
|
||||
"assets": "",
|
||||
"authorized_devices": "",
|
||||
@@ -322,10 +306,6 @@
|
||||
"cancel_search": "",
|
||||
"cannot_merge_people": "",
|
||||
"cannot_update_the_description": "",
|
||||
"cant_apply_changes": "",
|
||||
"cant_get_faces": "",
|
||||
"cant_search_people": "",
|
||||
"cant_search_places": "",
|
||||
"change_date": "",
|
||||
"change_expiration_time": "",
|
||||
"change_location": "",
|
||||
@@ -411,13 +391,6 @@
|
||||
"download": "",
|
||||
"downloading": "",
|
||||
"duration": "",
|
||||
"durations": {
|
||||
"days": "",
|
||||
"hours": "",
|
||||
"minutes": "",
|
||||
"months": "",
|
||||
"years": ""
|
||||
},
|
||||
"edit_album": "",
|
||||
"edit_avatar": "",
|
||||
"edit_date": "",
|
||||
@@ -436,7 +409,6 @@
|
||||
"edited": "",
|
||||
"editor": "",
|
||||
"email": "",
|
||||
"empty_album": "",
|
||||
"empty_trash": "",
|
||||
"enable": "",
|
||||
"enabled": "",
|
||||
@@ -522,7 +494,6 @@
|
||||
"extension": "",
|
||||
"external": "",
|
||||
"external_libraries": "",
|
||||
"failed_to_get_people": "",
|
||||
"favorite": "",
|
||||
"favorite_or_unfavorite_photo": "",
|
||||
"favorites": "",
|
||||
@@ -534,14 +505,12 @@
|
||||
"filter_people": "",
|
||||
"find_them_fast": "",
|
||||
"fix_incorrect_match": "",
|
||||
"force_re-scan_library_files": "",
|
||||
"forward": "",
|
||||
"general": "",
|
||||
"get_help": "",
|
||||
"getting_started": "",
|
||||
"go_back": "",
|
||||
"go_to_search": "",
|
||||
"go_to_share_page": "",
|
||||
"group_albums_by": "",
|
||||
"has_quota": "",
|
||||
"hide_gallery": "",
|
||||
@@ -656,7 +625,6 @@
|
||||
"oldest_first": "",
|
||||
"online": "",
|
||||
"only_favorites": "",
|
||||
"only_refreshes_modified_files": "",
|
||||
"open_the_search_filters": "",
|
||||
"options": "",
|
||||
"organize_your_library": "",
|
||||
@@ -745,8 +713,6 @@
|
||||
"saved_settings": "",
|
||||
"say_something": "",
|
||||
"scan_all_libraries": "",
|
||||
"scan_all_library_files": "",
|
||||
"scan_new_library_files": "",
|
||||
"scan_settings": "",
|
||||
"search": "",
|
||||
"search_albums": "",
|
||||
@@ -777,7 +743,6 @@
|
||||
"selected": "",
|
||||
"send_message": "",
|
||||
"send_welcome_email": "",
|
||||
"server": "",
|
||||
"server_stats": "",
|
||||
"set": "",
|
||||
"set_as_album_cover": "",
|
||||
@@ -847,7 +812,6 @@
|
||||
"to_favorite": "",
|
||||
"toggle_settings": "",
|
||||
"toggle_theme": "",
|
||||
"toggle_visibility": "",
|
||||
"total_usage": "",
|
||||
"trash": "",
|
||||
"trash_all": "",
|
||||
@@ -855,11 +819,9 @@
|
||||
"trashed_items_will_be_permanently_deleted_after": "",
|
||||
"type": "",
|
||||
"unarchive": "",
|
||||
"unarchived": "",
|
||||
"unfavorite": "",
|
||||
"unhide_person": "",
|
||||
"unknown": "",
|
||||
"unknown_album": "",
|
||||
"unknown_year": "",
|
||||
"unlimited": "",
|
||||
"unlink_oauth": "",
|
||||
@@ -893,7 +855,6 @@
|
||||
"view_links": "",
|
||||
"view_next_asset": "",
|
||||
"view_previous_asset": "",
|
||||
"viewer": "",
|
||||
"waiting": "",
|
||||
"week": "",
|
||||
"welcome_to_immich": "",
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"about": "Quant a",
|
||||
"about": "Refrescar",
|
||||
"account": "Compte",
|
||||
"account_settings": "Configuració del compte",
|
||||
"acknowledge": "Reconeix",
|
||||
@@ -14,11 +14,11 @@
|
||||
"add_a_name": "Afegir un nom",
|
||||
"add_a_title": "Afegir un títol",
|
||||
"add_exclusion_pattern": "Afegir un patró d'exclusió",
|
||||
"add_import_path": "Afegir un camí d'importació",
|
||||
"add_import_path": "Afegir una ruta d'importació",
|
||||
"add_location": "Afegir la ubicació",
|
||||
"add_more_users": "Afegir més usuaris",
|
||||
"add_partner": "Afegir company/a",
|
||||
"add_path": "Afegir un camí",
|
||||
"add_path": "Afegir una ruta",
|
||||
"add_photos": "Afegir fotografies",
|
||||
"add_to": "Afegir a...",
|
||||
"add_to_album": "Afegir a un l'àlbum",
|
||||
@@ -27,12 +27,18 @@
|
||||
"added_to_favorites": "Afegit als preferits",
|
||||
"added_to_favorites_count": "{count, number} afegits als preferits",
|
||||
"admin": {
|
||||
"add_exclusion_pattern_description": "Afegeix patrons d'eclusió. És permès de l'ús de *, **, i ? (globbing). Per a ignorar els fitxers de qualsevol directori anomenat \"Raw\" introduïu \"**/Raw/**\". Per a ignorar els fitxers acabats en \".tif\" introduïu \"**/*.tif\". Per a ignorar un camí absolut, utilitzeu \"/camí/a/ignorar/**\".",
|
||||
"add_exclusion_pattern_description": "Afegeix patrons d'exclusió. Es permet englobar fent ús de *, **, i ?. Per a ignorar els fitxers de qualsevol directori anomenat \"Raw\" introduïu \"**/Raw/**\". Per a ignorar els fitxers acabats en \".tif\" introduïu \"**/*.tif\". Per a ignorar una ruta absoluta, utilitzeu \"/ruta/a/ignorar/**\".",
|
||||
"asset_offline_description": "Aquest recurs de la biblioteca externa ja no es troba al disc i s'ha mogut a la paperera. Si el fitxer s'ha mogut dins de la biblioteca, comproveu la vostra línia de temps per trobar el nou recurs corresponent. Per restaurar aquest recurs, assegureu-vos que Immich pugui accedir a la ruta del fitxer següent i escanegeu la biblioteca.",
|
||||
"authentication_settings": "Configuració de l'autenticació",
|
||||
"authentication_settings_description": "Gestiona la contrasenya, OAuth i altres configuracions de l'autenticació",
|
||||
"authentication_settings_disable_all": "Estàs segur que vols desactivar tots els mètodes d'inici de sessió? L'inici de sessió quedarà completament desactivat.",
|
||||
"authentication_settings_reenable": "Per a tornar a habilitar, empra una <link>Comanda de Servidor</link>.",
|
||||
"background_task_job": "Tasques en segon pla",
|
||||
"backup_database": "Còpia de la base de dades",
|
||||
"backup_database_enable_description": "Habilitar còpies de la base de dades",
|
||||
"backup_keep_last_amount": "Quantitat de còpies de seguretat anteriors per conservar",
|
||||
"backup_settings": "Ajustes de les còpies de seguretat",
|
||||
"backup_settings_description": "Gestionar la configuració de la còpia de seguretat de la base de dades",
|
||||
"check_all": "Marca-ho tot",
|
||||
"cleared_jobs": "Tasques esborrades per a: {job}",
|
||||
"config_set_by_file": "La configuració està definida per un fitxer de configuració",
|
||||
@@ -42,16 +48,17 @@
|
||||
"confirm_reprocess_all_faces": "Esteu segur que voleu reprocessar totes les cares? Això també esborrarà la gent que heu anomenat.",
|
||||
"confirm_user_password_reset": "Esteu segur que voleu reinicialitzar la contrasenya de l'usuari {user}?",
|
||||
"create_job": "Crear tasca",
|
||||
"crontab_guru": "Crontab Guru",
|
||||
"cron_expression": "Expressió Cron",
|
||||
"cron_expression_description": "Estableix l'interval d'escaneig amb el format cron. Per obtenir més informació, consulteu, p.e <link>Crontab Guru</link>",
|
||||
"cron_expression_presets": "Ajustos predefinits d'expressions Cron",
|
||||
"disable_login": "Deshabiliteu l'inici de sessió",
|
||||
"disabled": "Deshabilitat",
|
||||
"duplicate_detection_job_description": "Executa l'aprenentatge automàtic en els elements per a detectar imatges semblants. Fa servir l'Smart Search",
|
||||
"exclusion_pattern_description": "Els patrons d'exclusió permeten ignorar fitxers i carpetes quan escanegeu una llibreria. Això és útil si teniu carpetes que contenen fitxer que no voleu importar, com els fitxers RAW.",
|
||||
"external_library_created_at": "Llibreria externa (creada el {date})",
|
||||
"external_library_management": "Gestió de llibreries externes",
|
||||
"face_detection": "Detecció de cares",
|
||||
"face_detection_description": "Detecta les cares fent servir aprenentatge automàtic. Per a videos només és té en compte la miniatura. \"Tot\" reprocessa tots els elements. \"Pendent\" encua els elements que encar no han estat processats. Les cares detectades s'encuaran per al Reconeixement Facial després de completar la Detecció Facial, tot agrupant-les entre noves persones o les ja existents.",
|
||||
"facial_recognition_job_description": "Agrupa les cares detectades per persona. Aquest pas s'executa després de completar la detecció de cares. \"Tot\" reagrupa totes les cares. \"Pendent\" encua les cares que no tenen cap persona assignada.",
|
||||
"face_detection_description": "Detecta les cares fent servir aprenentatge automàtic. Per a videos només és té en compte la miniatura. \"Actualitzar\" reprocessa tots els elements. \"Resetejar\" esborra tota la informació de cares actuals. \"Pendent\" afegeix a la cua els elements que encara no han estat processats. Les cares detectades s'afegiran a la cua per al Reconeixement Facial després de completar la Detecció Facial, tot agrupant-les entre noves persones o les ja existents.",
|
||||
"facial_recognition_job_description": "Agrupa les cares detectades per persona. Aquest pas s'executa després de completar la detecció de cares. \"Resetejar\" reagrupa totes les cares. \"Pendent\" afegeix a la cua les cares que no tenen cap persona assignada.",
|
||||
"failed_job_command": "La comanda {command} ha fallat per la tasca: {job}",
|
||||
"force_delete_user_warning": "COMPTE: Aquesta acció eliminara immediatament l'usuari i els seus elements. Aquesta acció és irreversible i els fitxers no es poden recuperar.",
|
||||
"forcing_refresh_library_files": "Força l'actualització de tots els fitxers de les biblioteques",
|
||||
@@ -61,18 +68,17 @@
|
||||
"image_prefer_embedded_preview_setting_description": "Empra vista prèvia incrustada en les fotografies RAW com a entrada per al processament d'imatge, quan sigui possible. Aquesta acció pot produir colors més acurats en algunes imatges, però la qualitat de la vista prèvia depèn de la càmera i la imatge pot tenir més artefactes de compressió.",
|
||||
"image_prefer_wide_gamut": "Prefereix àmplia gamma",
|
||||
"image_prefer_wide_gamut_setting_description": "Uitlitza Display P3 per a les miniatures. Això preserva més bé la vitalitat de les imatges amb espais de color àmplis, però les imatges es poden veure diferent en aparells antics amb una versió antiga del navegador. Les imatges sRGB romandran com a sRGB per a evitar canvis de color.",
|
||||
"image_preview_format": "Format de previsualització",
|
||||
"image_preview_resolution": "Resolució de previsualització",
|
||||
"image_preview_resolution_description": "S'empra al visualitzar una única fotografia i per a l'Aprenentatge Automàtic. L'alta resolució por preservar més detalls però es triga més a codificar, té fitxers més pesats i pot reduir la resposta de l'aplicació.",
|
||||
"image_preview_description": "Imatge de mida mitjana amb metadades eliminades, que s'utilitza quan es visualitza un sol recurs i per a l'aprenentatge automàtic",
|
||||
"image_preview_quality_description": "Vista prèvia de la qualitat de l'1 al 100. Més alt és millor, però produeix fitxers més grans i pot reduir la capacitat de resposta de l'aplicació. Establir un valor baix pot afectar la qualitat de l'aprenentatge automàtic.",
|
||||
"image_preview_title": "Paràmetres de previsualització",
|
||||
"image_quality": "Qualitat",
|
||||
"image_quality_description": "Qualitat d'imatge de 1 a 100. Un valor més alt millora la qualitat però genera fitxers més pesats.",
|
||||
"image_resolution": "Resolució",
|
||||
"image_resolution_description": "Les resolucions més altes poden conservar més detalls però triguen més a codificar-se, tenen mides de fitxer més grans i poden reduir la capacitat de resposta de l'aplicació.",
|
||||
"image_settings": "Configuració d'imatges",
|
||||
"image_settings_description": "Gestiona la qualitat i resolució de les imatges generades",
|
||||
"image_thumbnail_format": "Format de la miniatura",
|
||||
"image_thumbnail_resolution": "Resolució de la miniatura",
|
||||
"image_thumbnail_resolution_description": "S'empra per a veure grups de fotos (cronologia, vista d'àlbum, etc.). L'alta resolució pot preservar més detalls però triguen més en codificar-se, tenen fitxers més pesats i poden reduir la reactivitat de l'aplicació.",
|
||||
"image_thumbnail_description": "Miniatura petita amb metadades eliminades, que s'utilitza quan es visualitzen grups de fotos com la línia de temps principal",
|
||||
"image_thumbnail_quality_description": "Qualitat de miniatura d'1 a 100. Més alt és millor, però produeix fitxers més grans i pot reduir la capacitat de resposta de l'aplicació.",
|
||||
"image_thumbnail_title": "Configuració de miniatures",
|
||||
"job_concurrency": "{job} concurrència",
|
||||
"job_created": "Tasca creada",
|
||||
"job_not_concurrency_safe": "Aquesta tasca no és segura per a la conconcurrència.",
|
||||
@@ -82,9 +88,6 @@
|
||||
"jobs_delayed": "{jobCount, plural, other {# posposades}}",
|
||||
"jobs_failed": "{jobCount, plural, other {# fallides}}",
|
||||
"library_created": "Bilbioteca creada: {library}",
|
||||
"library_cron_expression": "Expressió cron",
|
||||
"library_cron_expression_description": "Estableix l'interval d'escaneig utilitzant el format cron. Per a més informació, consulta per exemple, <link>Crontab Guru</link>",
|
||||
"library_cron_expression_presets": "Expressions cron predeterminades",
|
||||
"library_deleted": "Bilbioteca eliminada",
|
||||
"library_import_path_description": "Especifiqueu una carpeta a importar. Aquesta carpeta, incloses les seves subcarpetes, serà escanejada per cercar-hi imatges i vídeos.",
|
||||
"library_scanning": "Escaneig periòdic",
|
||||
@@ -151,7 +154,7 @@
|
||||
"metadata_settings_description": "Administrar la configuració de les metadades",
|
||||
"migration_job": "Migració",
|
||||
"migration_job_description": "Migra les miniatures d'elements i cares cap a la nova estructura de carpetes",
|
||||
"no_paths_added": "Cap camí afegit",
|
||||
"no_paths_added": "No s'ha afegit cap ruta",
|
||||
"no_pattern_added": "Cap patró aplicat",
|
||||
"note_apply_storage_label_previous_assets": "Nota: Per aplicar l'etiquetatge d'emmagatzematge a elements pujats prèviament, executeu la",
|
||||
"note_cannot_be_changed_later": "NOTA: Això és irreversible!",
|
||||
@@ -202,13 +205,12 @@
|
||||
"password_enable_description": "Inicia sessió amb correu electrònic i contrasenya",
|
||||
"password_settings": "Inici de sessió amb contrasenya",
|
||||
"password_settings_description": "Gestiona la configuració de l'inici de sessió amb contrasenya",
|
||||
"paths_validated_successfully": "Tots els camins han estat validats amb èxit",
|
||||
"paths_validated_successfully": "Totes les rutes han estat validades amb èxit",
|
||||
"person_cleanup_job": "Neteja de persona",
|
||||
"quota_size_gib": "Tamany de la quota (GiB)",
|
||||
"refreshing_all_libraries": "Actualitzant totes les biblioteques",
|
||||
"registration": "Registre d'administrador",
|
||||
"registration_description": "Com que ets el primer usuari del sistema, seràs designat com a administrador i seràs responsable de les tasques administratives. També seràs l'encarregat de crear usuaris addicionals.",
|
||||
"removing_deleted_files": "Eliminant fitxers fora de línia",
|
||||
"repair_all": "Reparar tot",
|
||||
"repair_matched_items": "Coincidència {count, plural, one {# element} other {# elements}}",
|
||||
"repaired_items": "Corregit {count, plural, one {# element} other {# elements}}",
|
||||
@@ -216,8 +218,6 @@
|
||||
"reset_settings_to_default": "Restablir configuracions per defecte",
|
||||
"reset_settings_to_recent_saved": "Restablir la configuració guardada més recent",
|
||||
"scanning_library": "Escanejant biblioteca",
|
||||
"scanning_library_for_changed_files": "Escanejant llibreria per trobar fitxers modificats",
|
||||
"scanning_library_for_new_files": "Escanejant llibreria per trobar fitxers nous",
|
||||
"search_jobs": "Tasques de cerca...",
|
||||
"send_welcome_email": "Enviar correu electrònic de benvinguda",
|
||||
"server_external_domain_settings": "Domini extern",
|
||||
@@ -254,7 +254,6 @@
|
||||
"these_files_matched_by_checksum": "Aquests fitxers coincideixen amb els seus checksums",
|
||||
"thumbnail_generation_job": "Generar miniatures",
|
||||
"thumbnail_generation_job_description": "Genera miniatures grans, petites i borroses per a cada element, així com miniatures per a cada persona",
|
||||
"transcode_policy_description": "",
|
||||
"transcoding_acceleration_api": "API d'acceleració",
|
||||
"transcoding_acceleration_api_description": "L'API que interactuarà amb el vostre dispositiu per accelerar la transcodificació. Aquesta configuració és \"millor esforç\": tornarà a la transcodificació del programari en cas d'error. VP9 pot funcionar o no depenent del vostre maquinari.",
|
||||
"transcoding_acceleration_nvenc": "NVENC (requereix GPU d'NVIDIA)",
|
||||
@@ -280,7 +279,7 @@
|
||||
"transcoding_hardware_acceleration": "Acceleració de maquinari",
|
||||
"transcoding_hardware_acceleration_description": "Experimental. Molt més ràpid, però tindrà una qualitat més baixa amb la mateixa taxa de bits",
|
||||
"transcoding_hardware_decoding": "Descodificació de maquinari",
|
||||
"transcoding_hardware_decoding_setting_description": "S'aplica només a NVENC, QSV i RKMPP. Permet l'acceleració d'extrem a extrem en lloc d'accelerar només la codificació. És possible que no funcioni en tots els vídeos.",
|
||||
"transcoding_hardware_decoding_setting_description": "Habilita l'acceleració d'extrem a extrem en lloc d'accelerar només la codificació. És possible que no funcioni en tots els vídeos.",
|
||||
"transcoding_hevc_codec": "Còdec HEVC",
|
||||
"transcoding_max_b_frames": "Nombre màxim de B-frames",
|
||||
"transcoding_max_b_frames_description": "Els valors més alts milloren l'eficiència de la compressió, però alenteixen la codificació. És possible que no sigui compatible amb l'acceleració de maquinari en dispositius antics. 0 desactiva els B-frames, mentre que -1 estableix aquest valor automàticament.",
|
||||
@@ -306,8 +305,6 @@
|
||||
"transcoding_threads_description": "Els valors més alts condueixen a una codificació més ràpida, però deixen menys espai perquè el servidor processi altres tasques mentre està actiu. Aquest valor no hauria de ser superior al nombre de nuclis de CPU. Maximitza la utilització si s'estableix a 0.",
|
||||
"transcoding_tone_mapping": "Mapeig de to",
|
||||
"transcoding_tone_mapping_description": "Intenta preservar l'aspecte dels vídeos HDR quan es converteixen a SDR. Cada algorisme fa diferents compensacions pel color, el detall i la brillantor. Hable conserva els detalls, Mobius conserva el color i Reinhard conserva la brillantor.",
|
||||
"transcoding_tone_mapping_npl": "NPL de mapatge de to",
|
||||
"transcoding_tone_mapping_npl_description": "Els colors s'ajustaran perquè semblin normals per a exposicions amb aquesta brillantor. Contra intuïtivament, els valors més baixos augmenten la brillantor del vídeo i viceversa, ja que compensa la brillantor de la pantalla. 0 estableix aquest valor automàticament.",
|
||||
"transcoding_transcode_policy": "Política de transcodificació",
|
||||
"transcoding_transcode_policy_description": "Política sobre quan s'ha de transcodificar un vídeo. Els vídeos HDR sempre es transcodificaran (excepte si la transcodificació està desactivada).",
|
||||
"transcoding_two_pass_encoding": "Codificació de dues passades",
|
||||
@@ -388,7 +385,6 @@
|
||||
"archive_or_unarchive_photo": "Arxivar o desarxivar fotografia",
|
||||
"archive_size": "Mida de l'arxiu",
|
||||
"archive_size_description": "Configureu la mida de l'arxiu de les descàrregues (en GiB)",
|
||||
"archived": "Arxivat",
|
||||
"archived_count": "{count, plural, one {Arxivat #} other {Arxivats #}}",
|
||||
"are_these_the_same_person": "Són la mateixa persona?",
|
||||
"are_you_sure_to_do_this": "Esteu segurs que voleu fer-ho?",
|
||||
@@ -399,7 +395,7 @@
|
||||
"asset_has_unassigned_faces": "L'element té cares no assignades",
|
||||
"asset_hashing": "Hashing...",
|
||||
"asset_offline": "Element fora de línia",
|
||||
"asset_offline_description": "Aquest element està fora de línia. L'Immich no pot accedir a la seva ubicació. Si us plau, assegureu-vos que l'actiu està disponible i després torneu la llibreria.",
|
||||
"asset_offline_description": "Aquest recurs extern ja no es troba al disc. Poseu-vos en contacte amb el vostre administrador d'Immich per obtenir ajuda.",
|
||||
"asset_skipped": "Saltat",
|
||||
"asset_skipped_in_trash": "A la paperera",
|
||||
"asset_uploaded": "Carregat",
|
||||
@@ -412,7 +408,7 @@
|
||||
"assets_moved_to_trash_count": "{count, plural, one {# recurs mogut} other {# recursos moguts}} a la paperera",
|
||||
"assets_permanently_deleted_count": "{count, plural, one {# recurs esborrat} other {# recursos esborrats}} permanentment",
|
||||
"assets_removed_count": "{count, plural, one {# element eliminat} other {# elements eliminats}}",
|
||||
"assets_restore_confirmation": "Esteu segurs que voleu restaurar tots els teus actius? Aquesta acció no es pot desfer!",
|
||||
"assets_restore_confirmation": "Esteu segurs que voleu restaurar tots els teus actius? Aquesta acció no es pot desfer! Tingueu en compte que els recursos fora de línia no es poden restaurar d'aquesta manera.",
|
||||
"assets_restored_count": "{count, plural, one {# element restaurat} other {# elements restaurats}}",
|
||||
"assets_trashed_count": "{count, plural, one {# element enviat} other {# elements enviats}} a la paperera",
|
||||
"assets_were_part_of_album_count": "{count, plural, one {L'element ja és} other {Els elements ja són}} part de l'àlbum",
|
||||
@@ -423,6 +419,7 @@
|
||||
"birthdate_saved": "Data de naixement guardada amb èxit",
|
||||
"birthdate_set_description": "La data de naixement s'utilitza per calcular l'edat d'aquesta persona en el moment d'una foto.",
|
||||
"blurred_background": "Fons difuminat",
|
||||
"bugs_and_feature_requests": "Errors i sol·licituds de funcions",
|
||||
"build": "Construeix",
|
||||
"build_image": "Construeix la imatge",
|
||||
"bulk_delete_duplicates_confirmation": "Esteu segur que voleu suprimir de manera massiva {count, plural, one {# recurs duplicat} other {# recursos duplicats}}? Això mantindrà el recurs més gran de cada grup i esborrarà permanentment tots els altres duplicats. No podeu desfer aquesta acció!",
|
||||
@@ -437,10 +434,6 @@
|
||||
"cannot_merge_people": "No es pot fusionar gent",
|
||||
"cannot_undo_this_action": "Aquesta acció no es pot desfer!",
|
||||
"cannot_update_the_description": "No es pot actualitzar la descripció",
|
||||
"cant_apply_changes": "No es poden aplicar els canvis",
|
||||
"cant_get_faces": "No es poden obtenir les cares",
|
||||
"cant_search_people": "No es pot buscar gent",
|
||||
"cant_search_places": "No es poden cercar llocs",
|
||||
"change_date": "Canvia la data",
|
||||
"change_expiration_time": "Canvia la data d'expiració",
|
||||
"change_location": "Canvia la ubicació",
|
||||
@@ -519,18 +512,20 @@
|
||||
"delete_api_key_prompt": "Esteu segurs que voleu eliminar aquesta clau API?",
|
||||
"delete_duplicates_confirmation": "Esteu segurs que voleu eliminar aquests duplicats permanentment?",
|
||||
"delete_key": "Suprimeix la clau",
|
||||
"delete_library": "Suprimeix la llibreria",
|
||||
"delete_library": "Suprimeix la Llibreria",
|
||||
"delete_link": "Esborra l'enllaç",
|
||||
"delete_shared_link": "Odstranit sdílený odkaz",
|
||||
"delete_tag": "Eliminar etiqueta",
|
||||
"delete_tag_confirmation_prompt": "Estàs segur que vols eliminar l'etiqueta {tagName}?",
|
||||
"delete_user": "Suprimeix l'usuari",
|
||||
"deleted_shared_link": "Suprimeix l'enllaç compartit",
|
||||
"deletes_missing_assets": "Elimina els actius que falten del disc",
|
||||
"description": "Descripció",
|
||||
"details": "Detalls",
|
||||
"direction": "Direcció",
|
||||
"disabled": "Desactivat",
|
||||
"disallow_edits": "No permetre les edicions",
|
||||
"discord": "Discord",
|
||||
"discover": "Descobreix",
|
||||
"dismiss_all_errors": "Descarta tots els errors",
|
||||
"dismiss_error": "Descarta l'error",
|
||||
@@ -539,6 +534,7 @@
|
||||
"display_original_photos": "Mostra les fotografies originals",
|
||||
"display_original_photos_setting_description": "Preferiu mostrar la foto original quan visualitzeu un recurs en lloc de miniatures quan el recurs original és compatible amb el web. Això pot provocar una velocitat de visualització de fotos més lenta.",
|
||||
"do_not_show_again": "No tornis a mostrar aquest missatge",
|
||||
"documentation": "Documentació",
|
||||
"done": "Fet",
|
||||
"download": "Descarregar",
|
||||
"download_include_embedded_motion_videos": "Vídeos incrustats",
|
||||
@@ -551,13 +547,6 @@
|
||||
"duplicates": "Duplicats",
|
||||
"duplicates_description": "Resol cada grup indicant quins, si n'hi ha, són duplicats",
|
||||
"duration": "Duració",
|
||||
"durations": {
|
||||
"days": "",
|
||||
"hours": "",
|
||||
"minutes": "",
|
||||
"months": "",
|
||||
"years": ""
|
||||
},
|
||||
"edit": "Editar",
|
||||
"edit_album": "Edita l'àlbum",
|
||||
"edit_avatar": "Edita l'avatar",
|
||||
@@ -565,8 +554,8 @@
|
||||
"edit_date_and_time": "Edita data i hora",
|
||||
"edit_exclusion_pattern": "Edita patró d'exclusió",
|
||||
"edit_faces": "Edita les cares",
|
||||
"edit_import_path": "Edita el camí d'importació",
|
||||
"edit_import_paths": "Edita camins d'importació",
|
||||
"edit_import_path": "Edita la ruta d'importació",
|
||||
"edit_import_paths": "Edita les rutes d'importació",
|
||||
"edit_key": "Edita clau",
|
||||
"edit_link": "Edita enllaç",
|
||||
"edit_location": "Edita ubicació",
|
||||
@@ -582,8 +571,6 @@
|
||||
"editor_crop_tool_h2_aspect_ratios": "Relació d'aspecte",
|
||||
"editor_crop_tool_h2_rotation": "Rotació",
|
||||
"email": "Correu electrònic",
|
||||
"empty": "",
|
||||
"empty_album": "",
|
||||
"empty_trash": "Buidar la paperera",
|
||||
"empty_trash_confirmation": "Esteu segur que voleu buidar la paperera? Això eliminarà tots els recursos a la paperera permanentment d'Immich.\nNo podeu desfer aquesta acció!",
|
||||
"enable": "Activar",
|
||||
@@ -623,7 +610,7 @@
|
||||
"failed_to_remove_product_key": "No s'ha pogut eliminar la clau del producte",
|
||||
"failed_to_stack_assets": "No s'han pogut apilar els elements",
|
||||
"failed_to_unstack_assets": "No s'han pogut desapilar els elements",
|
||||
"import_path_already_exists": "Aquest camí d'importació ja existeix.",
|
||||
"import_path_already_exists": "Aquesta ruta d'importació ja existeix.",
|
||||
"incorrect_email_or_password": "Correu electrònic o contrasenya incorrectes",
|
||||
"paths_validation_failed": "{paths, plural, one {# ruta} other {# rutes}} no ha pogut validar",
|
||||
"profile_picture_transparent_pixels": "Les fotos de perfil no poden tenir píxels transparents. Per favor, feu zoom in, mogueu la imatge o ambdues.",
|
||||
@@ -633,7 +620,7 @@
|
||||
"unable_to_add_assets_to_shared_link": "No s'han pogut afegir els elements a l'enllaç compartit",
|
||||
"unable_to_add_comment": "No es pot afegir el comentari",
|
||||
"unable_to_add_exclusion_pattern": "No s'ha pogut afegir el patró d’exclusió",
|
||||
"unable_to_add_import_path": "No s'ha pogut afegir el camí d'importació",
|
||||
"unable_to_add_import_path": "No s'ha pogut afegir la ruta d'importació",
|
||||
"unable_to_add_partners": "No es poden afegir companys",
|
||||
"unable_to_add_remove_archive": "No s'ha pogut {archived, select, true {eliminar l'element de} other {afegir l'element a}} l'arxiu",
|
||||
"unable_to_add_remove_favorites": "No s'ha pogut {favorite, select, true {afegir l'element als} other {eliminar l'element dels}} preferits",
|
||||
@@ -644,8 +631,6 @@
|
||||
"unable_to_change_location": "No es pot canviar la ubicació",
|
||||
"unable_to_change_password": "No es pot canviar la contrasenya",
|
||||
"unable_to_change_visibility": "No es pot canviar la visibilitat de {count, plural, one {# persona} other {# persones}}",
|
||||
"unable_to_check_item": "",
|
||||
"unable_to_check_items": "",
|
||||
"unable_to_complete_oauth_login": "No es pot completar l'inici de sessió OAuth",
|
||||
"unable_to_connect": "No pot connectar",
|
||||
"unable_to_connect_to_server": "No es pot connectar al servidor",
|
||||
@@ -686,12 +671,10 @@
|
||||
"unable_to_remove_album_users": "No es poden eliminar usuaris de l'àlbum",
|
||||
"unable_to_remove_api_key": "No es pot eliminar la clau de l'API",
|
||||
"unable_to_remove_assets_from_shared_link": "No es poden eliminar recursos de l'enllaç compartit",
|
||||
"unable_to_remove_comment": "",
|
||||
"unable_to_remove_deleted_assets": "No es poden eliminar els fitxers fora de línia",
|
||||
"unable_to_remove_library": "No es pot eliminar la biblioteca",
|
||||
"unable_to_remove_partner": "No es pot eliminar company/a",
|
||||
"unable_to_remove_reaction": "No es pot eliminar la reacció",
|
||||
"unable_to_remove_user": "",
|
||||
"unable_to_repair_items": "No es poden reparar els elements",
|
||||
"unable_to_reset_password": "No es pot restablir la contrasenya",
|
||||
"unable_to_resolve_duplicate": "No es pot resoldre el duplicat",
|
||||
@@ -721,10 +704,6 @@
|
||||
"unable_to_update_user": "No es pot actualitzar l'usuari",
|
||||
"unable_to_upload_file": "No es pot carregar el fitxer"
|
||||
},
|
||||
"every_day_at_onepm": "",
|
||||
"every_night_at_midnight": "",
|
||||
"every_night_at_twoam": "",
|
||||
"every_six_hours": "",
|
||||
"exif": "Exif",
|
||||
"exit_slideshow": "Surt de la presentació de diapositives",
|
||||
"expand_all": "Ampliar-ho tot",
|
||||
@@ -739,33 +718,27 @@
|
||||
"external": "Extern",
|
||||
"external_libraries": "Llibreries externes",
|
||||
"face_unassigned": "Sense assignar",
|
||||
"failed_to_get_people": "",
|
||||
"favorite": "Preferit",
|
||||
"favorite_or_unfavorite_photo": "Foto preferida o no preferida",
|
||||
"favorites": "Preferits",
|
||||
"feature": "",
|
||||
"feature_photo_updated": "Foto destacada actualitzada",
|
||||
"featurecollection": "",
|
||||
"features": "Característiques",
|
||||
"features_setting_description": "Administrar les funcions de l'aplicació",
|
||||
"file_name": "Nom de l'arxiu",
|
||||
"file_name_or_extension": "Nom de l'arxiu o extensió",
|
||||
"filename": "Nom del fitxer",
|
||||
"files": "",
|
||||
"filetype": "Tipus d'arxiu",
|
||||
"filter_people": "Filtra persones",
|
||||
"find_them_fast": "Trobeu-los ràpidament pel nom amb la cerca",
|
||||
"fix_incorrect_match": "Corregiu la coincidència incorrecta",
|
||||
"folders": "Carpetes",
|
||||
"folders_feature_description": "Explorar la vista de carpetes per les fotos i vídeos del sistema d'arxius",
|
||||
"force_re-scan_library_files": "Força a tornar a escanejar tots els fitxers de la biblioteca",
|
||||
"forward": "Endavant",
|
||||
"general": "General",
|
||||
"get_help": "Aconseguir ajuda",
|
||||
"getting_started": "Començant",
|
||||
"go_back": "Torna",
|
||||
"go_to_search": "Vés a cercar",
|
||||
"go_to_share_page": "Vés a la pàgina de compartir",
|
||||
"group_albums_by": "Agrupa àlbums per...",
|
||||
"group_no": "Cap agrupació",
|
||||
"group_owner": "Agrupar per propietari",
|
||||
@@ -791,7 +764,6 @@
|
||||
"image_alt_text_date_place_2_people": "{isVideo, select, true {Video} other {Image}} pres/a a {city}, {country} amb {person1} i {person2} el {date}",
|
||||
"image_alt_text_date_place_3_people": "{isVideo, select, true {Video} other {Image}} pres/a a {city}, {country} amb {person1}, {person2}, i {person3} el {date}",
|
||||
"image_alt_text_date_place_4_or_more_people": "{isVideo, select, true {Video} other {Image}} pres/a a {city}, {country} amb {person1}, {person2}, i {additionalCount, number} altres el {date}",
|
||||
"img": "",
|
||||
"immich_logo": "Logotip d'Immich",
|
||||
"immich_web_interface": "Interfície web Immich",
|
||||
"import_from_json": "Importar des de JSON",
|
||||
@@ -812,7 +784,6 @@
|
||||
"invite_people": "Convida gent",
|
||||
"invite_to_album": "Convida a l'àlbum",
|
||||
"items_count": "{count, plural, one {# element} other {# elements}}",
|
||||
"job_settings_description": "",
|
||||
"jobs": "Tasques",
|
||||
"keep": "Mantenir",
|
||||
"keep_all": "Mantenir-ho tot",
|
||||
@@ -827,19 +798,6 @@
|
||||
"level": "Nivell",
|
||||
"library": "Bibilioteca",
|
||||
"library_options": "Opcions de biblioteca",
|
||||
"license_activated_title": "La vostra llicència ha estat activada amb èxit",
|
||||
"license_button_activate": "Activar",
|
||||
"license_button_buy": "Comprar",
|
||||
"license_button_select": "Seleccionar",
|
||||
"license_individual_title": "Llicència individual",
|
||||
"license_info_unlicensed": "Sense llicència",
|
||||
"license_license_title": "LLICÈNCIA",
|
||||
"license_per_server": "Per servidor",
|
||||
"license_per_user": "Per usuari",
|
||||
"license_server_description_1": "1 llicència per servidor",
|
||||
"license_server_title": "Llicència de servidor",
|
||||
"license_trial_info_2": "Heu utilitzat l'Immich durant uns",
|
||||
"license_trial_info_3": "{accountAge, plural, one {# dia} other {# dies}}",
|
||||
"light": "Llum",
|
||||
"like_deleted": "M'agrada suprimit",
|
||||
"link_motion_video": "Enllaçar vídeo en moviment",
|
||||
@@ -861,8 +819,9 @@
|
||||
"look": "Aspecte",
|
||||
"loop_videos": "Vídeos en bucle",
|
||||
"loop_videos_description": "Habilita la reproducció en bucle del vídeo en els detalls.",
|
||||
"main_branch_warning": "Esteu usant una versió de desenvolupaent. Recomanem fer servir una versió publicada!",
|
||||
"make": "Fabricant",
|
||||
"manage_shared_links": "Spravovat sdílené odkazy",
|
||||
"manage_shared_links": "Administrar enllaços compartits",
|
||||
"manage_sharing_with_partners": "Gestiona la compartició amb els companys",
|
||||
"manage_the_app_settings": "Gestioneu la configuració de l'aplicació",
|
||||
"manage_your_account": "Gestiona el teu compte",
|
||||
@@ -930,6 +889,7 @@
|
||||
"notifications": "Notificacions",
|
||||
"notifications_setting_description": "Gestiona les notificacions",
|
||||
"oauth": "OAuth",
|
||||
"official_immich_resources": "Recursos oficials d'Immich",
|
||||
"offline": "Fora de línia",
|
||||
"offline_paths": "Rutes fora de línia",
|
||||
"offline_paths_description": "Aquests resultats poden ser deguts a la supressió manual de fitxers que no formen part d'una biblioteca externa.",
|
||||
@@ -942,7 +902,6 @@
|
||||
"onboarding_welcome_user": "Benvingut, {user}",
|
||||
"online": "En línia",
|
||||
"only_favorites": "Només preferits",
|
||||
"only_refreshes_modified_files": "Només actualitza els fitxers modificats",
|
||||
"open_in_map_view": "Obrir a la vista del mapa",
|
||||
"open_in_openstreetmap": "Obre a OpenStreetMap",
|
||||
"open_the_search_filters": "Obriu els filtres de cerca",
|
||||
@@ -980,7 +939,6 @@
|
||||
"people_edits_count": "{count, plural, one {# persona editada} other {# persones editades}}",
|
||||
"people_feature_description": "Explorar fotos i vídeos agrupades per persona",
|
||||
"people_sidebar_description": "Mostrar un enllaç a Persones a la barra lateral",
|
||||
"perform_library_tasks": "",
|
||||
"permanent_deletion_warning": "Avís d'eliminació permanent",
|
||||
"permanent_deletion_warning_setting_description": "Mostrar un avís quan s'eliminin els elements permanentment",
|
||||
"permanently_delete": "Eliminar permanentment",
|
||||
@@ -1002,7 +960,6 @@
|
||||
"play_memories": "Reproduir records",
|
||||
"play_motion_photo": "Reproduir Fotos en Moviment",
|
||||
"play_or_pause_video": "Reproduir o posar en pausa el vídeo",
|
||||
"point": "",
|
||||
"port": "Port",
|
||||
"preset": "Preestablert",
|
||||
"preview": "Previsualització",
|
||||
@@ -1047,12 +1004,10 @@
|
||||
"purchase_server_description_2": "Estat del contribuent",
|
||||
"purchase_server_title": "Servidor",
|
||||
"purchase_settings_server_activated": "La clau de producte del servidor la gestiona l'administrador",
|
||||
"range": "",
|
||||
"rating": "Valoració",
|
||||
"rating_clear": "Esborrar valoració",
|
||||
"rating_count": "{count, plural, one {# estrella} other {# estrelles}}",
|
||||
"rating_description": "Mostrar la valoració EXIF al panell d'informació",
|
||||
"raw": "",
|
||||
"reaction_options": "Opcions de reacció",
|
||||
"read_changelog": "Llegeix el registre de canvis",
|
||||
"reassign": "Reassignar",
|
||||
@@ -1063,11 +1018,13 @@
|
||||
"recent_searches": "Cerques recents",
|
||||
"refresh": "Actualitzar",
|
||||
"refresh_encoded_videos": "Actualitza vídeos codificats",
|
||||
"refresh_faces": "Actualitzar cares",
|
||||
"refresh_metadata": "Actualitzar les metadades",
|
||||
"refresh_thumbnails": "Actualitzar la miniatura",
|
||||
"refreshed": "Actualitzat",
|
||||
"refreshes_every_file": "Actualitza tots els fitxers",
|
||||
"refreshes_every_file": "Torna a llegir tots els fitxers existents i nous",
|
||||
"refreshing_encoded_video": "S'està actualitzant el vídeo codificat",
|
||||
"refreshing_faces": "Refrescant cares",
|
||||
"refreshing_metadata": "Actualitzant les metadades",
|
||||
"regenerating_thumbnails": "Regenerant les miniatures",
|
||||
"remove": "Eliminar",
|
||||
@@ -1095,7 +1052,6 @@
|
||||
"reset": "Restablir",
|
||||
"reset_password": "Restablir contrasenya",
|
||||
"reset_people_visibility": "Restablir la visibilitat de les persones",
|
||||
"reset_settings_to_default": "",
|
||||
"reset_to_default": "Restableix els valors predeterminats",
|
||||
"resolve_duplicates": "Resoldre duplicats",
|
||||
"resolved_all_duplicates": "Tots els duplicats resolts",
|
||||
@@ -1115,8 +1071,7 @@
|
||||
"saved_settings": "Configuració guardada",
|
||||
"say_something": "Digues quelcom",
|
||||
"scan_all_libraries": "Escanejar totes les llibreries",
|
||||
"scan_all_library_files": "Re-escanejar tots els fitxers de la llibreria",
|
||||
"scan_new_library_files": "Escanejar nous fitxers de la llibreria",
|
||||
"scan_library": "Escaneja",
|
||||
"scan_settings": "Configuració d'escaneig",
|
||||
"scanning_for_album": "S'està buscant l'àlbum...",
|
||||
"search": "Cerca",
|
||||
@@ -1159,7 +1114,6 @@
|
||||
"selected_count": "{count, plural, one {# seleccionat} other {# seleccionats}}",
|
||||
"send_message": "Envia missatge",
|
||||
"send_welcome_email": "Envia correu de benvinguda",
|
||||
"server": "Servidor",
|
||||
"server_offline": "Servidor fora de línia",
|
||||
"server_online": "Servidor en línia",
|
||||
"server_stats": "Estadístiques del servidor",
|
||||
@@ -1202,6 +1156,7 @@
|
||||
"show_person_options": "Mostra opcions de la persona",
|
||||
"show_progress_bar": "Mostra barra de progrés",
|
||||
"show_search_options": "Mostra opcions de cerca",
|
||||
"show_slideshow_transition": "Mostra la transició de la presentació de diapositives",
|
||||
"show_supporter_badge": "Insígnia de contribuent",
|
||||
"show_supporter_badge_description": "Mostra una insígnia de contributor",
|
||||
"shuffle": "Mescla",
|
||||
@@ -1243,13 +1198,16 @@
|
||||
"submit": "Envia",
|
||||
"suggestions": "Suggeriments",
|
||||
"sunrise_on_the_beach": "Albada a la platja",
|
||||
"support": "Suport",
|
||||
"support_and_feedback": "Suport i comentaris",
|
||||
"support_third_party_description": "La vostra instal·lació immich la va empaquetar un tercer. Els problemes que experimenteu poden ser causats per aquest paquet així que, si us plau, plantegeu els poblemes amb ells en primer lloc mitjançant els enllaços següents.",
|
||||
"swap_merge_direction": "Canvia la direcció d'unió",
|
||||
"sync": "Sincronitza",
|
||||
"tag": "Etiqueta",
|
||||
"tag_assets": "Etiquetar actius",
|
||||
"tag_created": "Etiqueta creada: {tag}",
|
||||
"tag_feature_description": "Exploreu fotos i vídeos agrupats per temes d'etiquetes lògiques",
|
||||
"tag_not_found_question": "No trobeu una etiqueta? Creeu-ne una <link>aquí</link>",
|
||||
"tag_not_found_question": "No trobeu una etiqueta? <link>Crear una nova etiqueta</link>",
|
||||
"tag_updated": "Etiqueta actualizada: {tag}",
|
||||
"tagged_assets": "{count, plural, one {#Etiquetat} other {#Etiquetats}} {count, plural, one {# actiu} other {# actius}}",
|
||||
"tags": "Etiquetes",
|
||||
@@ -1258,6 +1216,7 @@
|
||||
"theme_selection": "Selecció de tema",
|
||||
"theme_selection_description": "Activa automàticament el tema fosc o clar en funció de les preferències del sistema del navegador",
|
||||
"they_will_be_merged_together": "Es combinaran",
|
||||
"third_party_resources": "Recursos de tercers",
|
||||
"time_based_memories": "Records basats en el temps",
|
||||
"timezone": "Fus horari",
|
||||
"to_archive": "Arxivar",
|
||||
@@ -1268,7 +1227,6 @@
|
||||
"to_trash": "Paperera",
|
||||
"toggle_settings": "Canvia configuració",
|
||||
"toggle_theme": "Alternar tema",
|
||||
"toggle_visibility": "Canvia visibilitat",
|
||||
"total_usage": "Ús total",
|
||||
"trash": "Paperera",
|
||||
"trash_all": "Envia-ho tot a la paperera",
|
||||
@@ -1278,12 +1236,10 @@
|
||||
"trashed_items_will_be_permanently_deleted_after": "Els elements que s'enviïn a la paperera s'eliminaran permanentment després de {days, plural, one {# dia} other {# dies}}.",
|
||||
"type": "Tipus",
|
||||
"unarchive": "Desarxivar",
|
||||
"unarchived": "Desarxivat",
|
||||
"unarchived_count": "{count, plural, other {# elements desarxivats}}",
|
||||
"unfavorite": "Reverteix preferit",
|
||||
"unhide_person": "Mostra persona",
|
||||
"unknown": "Desconegut",
|
||||
"unknown_album": "Àlbum desconegut",
|
||||
"unknown_year": "Any desconegut",
|
||||
"unlimited": "Il·limitat",
|
||||
"unlink_motion_video": "Desvincular vídeo en moviment",
|
||||
@@ -1315,7 +1271,6 @@
|
||||
"use_custom_date_range": "Fes servir un rang de dates personalitzat",
|
||||
"user": "Usuari",
|
||||
"user_id": "ID d'usuari",
|
||||
"user_license_settings": "Llicència",
|
||||
"user_liked": "A {user} li ha agradat {type, select, photo {aquesta foto} video {aquest vídeo} asset {aquest recurs} other {}}",
|
||||
"user_purchase_settings": "Compra",
|
||||
"user_purchase_settings_description": "Gestiona la teva compra",
|
||||
@@ -1328,7 +1283,9 @@
|
||||
"variables": "Variables",
|
||||
"version": "Versió",
|
||||
"version_announcement_closing": "El teu amic Alex",
|
||||
"version_announcement_message": "Hola amic, hi ha una nova versió de l'aplicació, si us plau, preneu-vos el temps per visitar les <link>release notes</link> i assegureu-vos que el vostre <code>docker-compose.yml</code> i <code>.env</code> estàn actualitzats per evitar qualsevol configuració incorrecta, especialment si utilitzeu WatchTower o qualsevol mecanisme que gestioni l'actualització automàtica de la vostra aplicació.",
|
||||
"version_announcement_message": "Hola! Hi ha una nova versió d'Immich, si us plau, preneu-vos una estona per llegir les <link>notes de llançament</link> per assegurar que la teva configuració estigui actualitzada per evitar qualsevol error de configuració, especialment si utilitzeu WatchTower o qualsevol mecanisme que gestioni l'actualització automàtica de la vostra instància Immich.",
|
||||
"version_history": "Historial de versions",
|
||||
"version_history_item": "Instal·lat {version} el {date}",
|
||||
"video": "Vídeo",
|
||||
"video_hover_setting": "Reprodueix la miniatura en passar el ratolí",
|
||||
"video_hover_setting_description": "Reprodueix la miniatura quan el ratolí plana sobre l'element. Fins i tot quan estigui deshabilitat, la reproducció s'iniciarà planant sobre el botó de reproducció.",
|
||||
@@ -1343,7 +1300,6 @@
|
||||
"view_next_asset": "Mostra el següent element",
|
||||
"view_previous_asset": "Mostra l'element anterior",
|
||||
"view_stack": "Veure la pila",
|
||||
"viewer": "Visualitzador",
|
||||
"visibility_changed": "La visibilitat ha canviat per {count, plural, one {# persona} other {# persones}}",
|
||||
"waiting": "Esperant",
|
||||
"warning": "Avís",
|
||||
@@ -34,6 +34,11 @@
|
||||
"authentication_settings_disable_all": "Opravdu chcete zakázat všechny metody přihlášení? Přihlašování bude úplně zakázáno.",
|
||||
"authentication_settings_reenable": "Pro opětovné povolení použijte příkaz <link>Příkaz serveru</link>.",
|
||||
"background_task_job": "Úkoly na pozadí",
|
||||
"backup_database": "Zálohování databáze",
|
||||
"backup_database_enable_description": "Povolit zálohování databáze",
|
||||
"backup_keep_last_amount": "Počet předchozích záloh k uchování",
|
||||
"backup_settings": "Nastavení zálohování",
|
||||
"backup_settings_description": "Správa nastavení zálohování databáze",
|
||||
"check_all": "Vše zkontrolovat",
|
||||
"cleared_jobs": "Hotové úlohy pro: {job}",
|
||||
"config_set_by_file": "Konfigurace je aktuálně prováděna konfiguračním souborem",
|
||||
@@ -43,16 +48,17 @@
|
||||
"confirm_reprocess_all_faces": "Opravdu chcete znovu zpracovat všechny obličeje? Tím se vymažou i pojmenované osoby.",
|
||||
"confirm_user_password_reset": "Opravdu chcete obnovit heslo uživatele {user}?",
|
||||
"create_job": "Vytvořit úlohu",
|
||||
"crontab_guru": "Crontab Guru",
|
||||
"cron_expression": "Výraz cron",
|
||||
"cron_expression_description": "Nastavte interval prohledávání pomocí cron formátu. Další informace naleznete např. v <link>Crontab Guru</link>",
|
||||
"cron_expression_presets": "Předvolby výrazů cron",
|
||||
"disable_login": "Zakázat přihlášení",
|
||||
"disabled": "Zakázáno",
|
||||
"duplicate_detection_job_description": "Spuštění strojového učení na položkách za účelem detekce podobných obrázků. Spoléhá na Chytré vyhledávání",
|
||||
"exclusion_pattern_description": "Vzory vyloučení umožňují při prohledávání knihovny ignorovat soubory a složky. To je užitečné, pokud máte složky obsahující soubory, které nechcete importovat, například RAW soubory.",
|
||||
"external_library_created_at": "Externí knihovna (vytvořena {date})",
|
||||
"external_library_management": "Správa externích knihoven",
|
||||
"face_detection": "Detekce obličejů",
|
||||
"face_detection_description": "Detekce obličejů v obrázcích pomocí strojového učení. U videí se bere v úvahu pouze miniatura. \"Vše\" znovu zpracovává všechny položky. \"Chybějící\" zařadí do fronty položky, které ještě nebyly zpracovány. Zjištěné obličeje budou po dokončení funkce Rozpoznávání obličejů zařazeny do fronty a seskupeny do stávajících nebo nových osob.",
|
||||
"facial_recognition_job_description": "Seskupí nalezené obličeje do osob. Tento krok se spustí po dokončení detekce obličejů. \"Vše\" znovu seskupí všechny obličeje. \"Chybějící\" zpracuje obličeje, které nemají přiřazenou osobu.",
|
||||
"face_detection_description": "Detekce obličejů v obrázcích pomocí strojového učení. U videí se bere v úvahu pouze miniatura. „Obnovit“ znovu zpracuje všechny položky. „Resetovat“ navíc vymaže všechna aktuální data obličejů. „Chybějící“ zařadí do fronty položky, které ještě nebyly zpracovány. Zjištěné obličeje budou po dokončení funkce Rozpoznávání obličejů zařazeny do fronty a seskupeny do stávajících nebo nových osob.",
|
||||
"facial_recognition_job_description": "Seskupí nalezené obličeje do osob. Tento krok se spustí po dokončení detekce obličejů. „Resetovat“ znovu seskupí všechny obličeje. „Chybějící“ zpracuje obličeje, které nemají přiřazenou osobu.",
|
||||
"failed_job_command": "Příkaz {command} se nezdařil pro úlohu: {job}",
|
||||
"force_delete_user_warning": "UPOZORNĚNÍ: Tímto okamžitě odstraníte uživatele a všechny jeho položky. Tento krok nelze vrátit zpět a soubory nelze obnovit.",
|
||||
"forcing_refresh_library_files": "Vynucení obnovy všech souborů knihovny",
|
||||
@@ -63,22 +69,15 @@
|
||||
"image_prefer_wide_gamut": "Preferovat široký gamut",
|
||||
"image_prefer_wide_gamut_setting_description": "Použít Display P3 pro miniatury. To lépe zachovává živost obrázků s širokým barevným prostorem, ale obrázky se mohou na starých zařízeních se starou verzí prohlížeče zobrazovat jinak. sRGB obrázky jsou ponechány jako sRGB, aby se zabránilo posunům barev.",
|
||||
"image_preview_description": "Středně velký obrázek se zbavenými metadaty, který se používá při prohlížení jedné položky a pro strojové učení",
|
||||
"image_preview_format": "Formát náhledů",
|
||||
"image_preview_quality_description": "Kvalita náhledu od 1 do 100. Vyšší je lepší, ale vytváří větší soubory a může snížit responzivitu aplikace. Nastavení nízké hodnoty může ovlivnit kvalitu strojového učení.",
|
||||
"image_preview_resolution": "Rozlišení náhledů",
|
||||
"image_preview_resolution_description": "Používá se při prohlížení jedné fotografie a pro strojové učení. Vyšší rozlišení mohou zachovat více detailů, ale jejich kódování trvá déle, mají větší velikost souboru a mohou snížit odezvu aplikace.",
|
||||
"image_preview_title": "Náhledy",
|
||||
"image_quality": "Kvalita",
|
||||
"image_quality_description": "Kvalita obrazu od 1 do 100. Vyšší kvalita je lepší, ale vytváří větší soubory, tato volba ovlivňuje náhled a miniatury obrázků.",
|
||||
"image_resolution": "Rozlišení",
|
||||
"image_resolution_description": "Vyšší rozlišení mohou zachovat více detailů, ale jejich kódování trvá déle, mají větší velikost souboru a mohou snížit odezvu aplikace.",
|
||||
"image_settings": "Obrázky",
|
||||
"image_settings_description": "Správa kvality a rozlišení generovaných obrázků",
|
||||
"image_thumbnail_description": "Malá miniatura s odstraněnými metadaty, který se používá při prohlížení skupin fotografií, jako je hlavní časová osa",
|
||||
"image_thumbnail_format": "Formát miniatur",
|
||||
"image_thumbnail_quality_description": "Kvalita miniatur od 1 do 100. Vyšší je lepší, ale vytváří větší soubory a může snížit odezvu aplikace.",
|
||||
"image_thumbnail_resolution": "Rozlišení miniatur",
|
||||
"image_thumbnail_resolution_description": "Používá se při prohlížení skupin fotografií (hlavní časová osa, zobrazení alba atd.). Vyšší rozlišení může zachovat více detailů, ale trvá déle, než se zakóduje, má větší velikost souboru a může snížit odezvu aplikace.",
|
||||
"image_thumbnail_title": "Miniatury",
|
||||
"job_concurrency": "Souběžnost úlohy {job}",
|
||||
"job_created": "Úloha vytvořena",
|
||||
@@ -89,9 +88,6 @@
|
||||
"jobs_delayed": "{jobCount, plural, one {# zpožděný} few {# zpožděné} other {# zpožděných}}",
|
||||
"jobs_failed": "{jobCount, plural, one {# neúspěšný} few {# neúspěšné} other {# neúspěšných}}",
|
||||
"library_created": "Vytvořena knihovna: {library}",
|
||||
"library_cron_expression": "Výraz pro Cron",
|
||||
"library_cron_expression_description": "Nastavte interval prohledávání pomocí formátu cron. Další informace naleznete např. v <link>Crontab Guru</link>",
|
||||
"library_cron_expression_presets": "Předvolby výrazu pro Cron",
|
||||
"library_deleted": "Knihovna smazána",
|
||||
"library_import_path_description": "Zadejte složku, kterou chcete importovat. Tato složka bude prohledána včetně podsložek a budou v ní hledány obrázky a videa.",
|
||||
"library_scanning": "Pravidelné prohledávání",
|
||||
@@ -110,7 +106,7 @@
|
||||
"machine_learning_clip_model_description": "Název CLIP modelu je uvedený <link>zde</link>. Pamatujte, že při změně modelu je nutné znovu spustit úlohu 'Chytré vyhledávání' pro všechny obrázky.",
|
||||
"machine_learning_duplicate_detection": "Kontrola duplicit",
|
||||
"machine_learning_duplicate_detection_enabled": "Povolit kontrolu duplicit",
|
||||
"machine_learning_duplicate_detection_enabled_description": "Pokud je tato funkce vypnuta, budou identické položky stále duplikovány.",
|
||||
"machine_learning_duplicate_detection_enabled_description": "Pokud je tato funkce vypnuta, budou identické položky stále deduplikovány.",
|
||||
"machine_learning_duplicate_detection_setting_description": "Použít CLIP embeddings k nalezení pravděpodobných duplicit",
|
||||
"machine_learning_enabled": "Povolit strojové učení",
|
||||
"machine_learning_enabled_description": "Pokud je vypnuto, budou všechny funkce strojového učení vypnuty bez ohledu na níže uvedená nastavení.",
|
||||
@@ -215,7 +211,6 @@
|
||||
"refreshing_all_libraries": "Obnovení všech knihoven",
|
||||
"registration": "Registrace správce",
|
||||
"registration_description": "Vzhledem k tomu, že jste prvním uživatelem v systému, budete přiřazen jako správce a budete zodpovědný za úkoly správy a další uživatelé budou vytvořeni vámi.",
|
||||
"removing_deleted_files": "Odstranění offline souborů",
|
||||
"repair_all": "Opravit vše",
|
||||
"repair_matched_items": "Shoda {count, plural, one {# položky} other {# položek}}",
|
||||
"repaired_items": "{count, plural, one {Opravena # položka} few {Opraveny # položky} other {Opraveno # položek}}",
|
||||
@@ -223,8 +218,6 @@
|
||||
"reset_settings_to_default": "Obnovení výchozího nastavení",
|
||||
"reset_settings_to_recent_saved": "Obnovit poslední uložené nastavení",
|
||||
"scanning_library": "Prohledat knihovnu",
|
||||
"scanning_library_for_changed_files": "Hledání změněných souborů v knihovně",
|
||||
"scanning_library_for_new_files": "Hledání nových souborů v knihovně",
|
||||
"search_jobs": "Hledat úlohy...",
|
||||
"send_welcome_email": "Odeslat uvítací e-mail",
|
||||
"server_external_domain_settings": "Externí doména",
|
||||
@@ -261,7 +254,6 @@
|
||||
"these_files_matched_by_checksum": "Tyto soubory jsou porovnávány podle jejich kontrolních součtů",
|
||||
"thumbnail_generation_job": "Generování miniatur",
|
||||
"thumbnail_generation_job_description": "Generování velkých, malých a rozmazaných miniatur pro každý obrázek a miniatur pro každou osobu",
|
||||
"transcode_policy_description": "Zásady, kdy má být video překódováno. Videa HDR budou překódována vždy (kromě případů, kdy je překódování zakázáno).",
|
||||
"transcoding_acceleration_api": "API pro akceleraci",
|
||||
"transcoding_acceleration_api_description": "Rozhraní, které bude komunikovat se zařízením a urychlovat překódování. Toto nastavení je 'best effort': při selhání se vrátí k softwarovému překódování. VP9 může, ale nemusí fungovat v závislosti na vašem hardwaru.",
|
||||
"transcoding_acceleration_nvenc": "NVENC (vyžaduje NVIDIA GPU)",
|
||||
@@ -287,7 +279,7 @@
|
||||
"transcoding_hardware_acceleration": "Hardwarová akcelerace",
|
||||
"transcoding_hardware_acceleration_description": "Experimentální; mnohem rychlejší, ale při stejném datovém toku bude mít nižší kvalitu",
|
||||
"transcoding_hardware_decoding": "Hardwarové dekódování",
|
||||
"transcoding_hardware_decoding_setting_description": "Platí pouze pro NVENC, QSV a RKMPP. Povoluje kompletní akceleraci namísto akcelerace pouze kódování. Nemusí fungovat u všech videí.",
|
||||
"transcoding_hardware_decoding_setting_description": "Povoluje kompletní akceleraci namísto akcelerace pouze kódování. Nemusí fungovat u všech videí.",
|
||||
"transcoding_hevc_codec": "Kodek HEVC",
|
||||
"transcoding_max_b_frames": "Maximální počet B-snímků",
|
||||
"transcoding_max_b_frames_description": "Vyšší hodnoty zvyšují účinnost komprese, ale zpomalují kódování. Nemusí být kompatibilní s hardwarovou akcelerací na starších zařízeních. Hodnota 0 zakáže B-snímky, zatímco -1 tuto hodnotu nastaví automaticky.",
|
||||
@@ -313,8 +305,6 @@
|
||||
"transcoding_threads_description": "Vyšší hodnoty vedou k rychlejšímu kódování, ale ponechávají serveru méně prostoru pro zpracování jiných úloh. Tato hodnota by neměla být vyšší než počet jader procesoru. Maximalizuje využití, pokud je nastavena na 0.",
|
||||
"transcoding_tone_mapping": "Tone-mapping",
|
||||
"transcoding_tone_mapping_description": "Snaží se zachovat vzhled videí HDR při převodu na SDR. Každý algoritmus dělá různé kompromisy v oblasti barev, detailů a jasu. Hable zachovává detaily, Mobius zachovává barvy a Reinhard zachovává jas.",
|
||||
"transcoding_tone_mapping_npl": "Tone-mapping NPL",
|
||||
"transcoding_tone_mapping_npl_description": "Barvy budou upraveny tak, aby vypadaly normálně pro displej s tímto jasem. Nižší hodnoty naopak zvyšují jas videa a naopak, protože kompenzují jas displeje. Hodnota 0 nastavuje tuto hodnotu automaticky.",
|
||||
"transcoding_transcode_policy": "Zásady překódování",
|
||||
"transcoding_transcode_policy_description": "Zásady, kdy má být video překódováno. Videa HDR budou překódována vždy (kromě případů, kdy je překódování zakázáno).",
|
||||
"transcoding_two_pass_encoding": "Dvouprůchodové kódování",
|
||||
@@ -382,7 +372,7 @@
|
||||
"all_videos": "Všechna videa",
|
||||
"allow_dark_mode": "Povolit tmavý režim",
|
||||
"allow_edits": "Povolit úpravy",
|
||||
"allow_public_user_to_download": "Povolit veřejnosti stahování",
|
||||
"allow_public_user_to_download": "Povolit veřejnosti stahovat",
|
||||
"allow_public_user_to_upload": "Povolit veřejnosti nahrávat",
|
||||
"anti_clockwise": "Proti směru hodinových ručiček",
|
||||
"api_key": "API klíč",
|
||||
@@ -395,7 +385,6 @@
|
||||
"archive_or_unarchive_photo": "Archivovat nebo odarchivovat fotku",
|
||||
"archive_size": "Velikost archivu",
|
||||
"archive_size_description": "Nastavte velikost archivu pro stahování (v GiB)",
|
||||
"archived": "Archivováno",
|
||||
"archived_count": "{count, plural, other {Archivováno #}}",
|
||||
"are_these_the_same_person": "Jedná se o stejnou osobu?",
|
||||
"are_you_sure_to_do_this": "Opravdu to chcete udělat?",
|
||||
@@ -416,7 +405,6 @@
|
||||
"assets_added_to_album_count": "Do alba {count, plural, one {byla přidána # položka} few {byly přidány # položky} other {bylo přidáno # položek}}",
|
||||
"assets_added_to_name_count": "{count, plural, one {Přidána # položka} few {Přidány # položky} other {Přidáno # položek}} do {hasName, select, true {alba <b>{name}</b>} other {nového alba}}",
|
||||
"assets_count": "{count, plural, one {# položka} few {# položky} other {# položek}}",
|
||||
"assets_moved_to_trash": "{count, plural, one {# položka přesunuta} few {# položky přesunuty} other {# položek přesunuto}} do koše",
|
||||
"assets_moved_to_trash_count": "Do koše {count, plural, one {přesunuta # položka} few {přesunuty # položky} other {přesunuto # položek}}",
|
||||
"assets_permanently_deleted_count": "Trvale {count, plural, one {smazána # položka} few {smazány # položky} other {smazáno # položek}}",
|
||||
"assets_removed_count": "{count, plural, one {Odstraněna # položka} few {Odstraněny # položky} other {Odstraněno # položek}}",
|
||||
@@ -446,10 +434,6 @@
|
||||
"cannot_merge_people": "Nelze sloučit osoby",
|
||||
"cannot_undo_this_action": "Tuto akci nelze vrátit zpět!",
|
||||
"cannot_update_the_description": "Nelze aktualizovat popis",
|
||||
"cant_apply_changes": "Nelze uplatnit změny",
|
||||
"cant_get_faces": "Nelze získat obličeje",
|
||||
"cant_search_people": "Nelze vyhledávat lidi",
|
||||
"cant_search_places": "Nelze vyhledávat místa",
|
||||
"change_date": "Změnit datum",
|
||||
"change_expiration_time": "Změna konce platnosti",
|
||||
"change_location": "Změna polohy",
|
||||
@@ -481,6 +465,7 @@
|
||||
"confirm": "Potvrdit",
|
||||
"confirm_admin_password": "Potvrzení hesla správce",
|
||||
"confirm_delete_shared_link": "Opravdu chcete odstranit tento sdílený odkaz?",
|
||||
"confirm_keep_this_delete_others": "Všechny ostatní položky v tomto uskupení mimo této budou odstraněny. Opravdu chcete pokračovat?",
|
||||
"confirm_password": "Potvrzení hesla",
|
||||
"contain": "Obsah",
|
||||
"context": "Kontext",
|
||||
@@ -530,6 +515,7 @@
|
||||
"delete_key": "Smazat klíč",
|
||||
"delete_library": "Smazat knihovnu",
|
||||
"delete_link": "Smazat odkaz",
|
||||
"delete_others": "Odstranit ostatní",
|
||||
"delete_shared_link": "Smazat sdílený odkaz",
|
||||
"delete_tag": "Smazat značku",
|
||||
"delete_tag_confirmation_prompt": "Opravdu chcete odstranit značku {tagName}?",
|
||||
@@ -563,13 +549,6 @@
|
||||
"duplicates": "Duplicity",
|
||||
"duplicates_description": "Vyřešte každou skupinu tak, že uvedete, které skupiny jsou duplicitní",
|
||||
"duration": "Doba trvání",
|
||||
"durations": {
|
||||
"days": "{days, plural, one {den} few {{days, number} dny} other {{days, number} dní}}",
|
||||
"hours": "{hours, plural, one {hodina} few {{hours, number} hodiny} other {{hours, number} hodin}}",
|
||||
"minutes": "{minutes, plural, one {minuta} few {{minutes, number} minuty} other {{minutes, number} minut}}",
|
||||
"months": "{months, plural, one {měsíc} few {{months, number} měsíce} other {{months, number} měsíců}}",
|
||||
"years": "{years, plural, one {rok} few {{years, number} roky} other {{years, number} let}}"
|
||||
},
|
||||
"edit": "Upravit",
|
||||
"edit_album": "Upravit album",
|
||||
"edit_avatar": "Upravit avatar",
|
||||
@@ -594,8 +573,6 @@
|
||||
"editor_crop_tool_h2_aspect_ratios": "Poměr stran",
|
||||
"editor_crop_tool_h2_rotation": "Otočení",
|
||||
"email": "E-mail",
|
||||
"empty": "Prázdné",
|
||||
"empty_album": "Prázdné album",
|
||||
"empty_trash": "Vyprázdnit koš",
|
||||
"empty_trash_confirmation": "Opravdu chcete vysypat koš? Tím se z Immiche trvale odstraní všechny položky v koši.\nTuto akci nelze vrátit zpět!",
|
||||
"enable": "Povolit",
|
||||
@@ -629,6 +606,7 @@
|
||||
"failed_to_create_shared_link": "Nepodařilo se vytvořit sdílený odkaz",
|
||||
"failed_to_edit_shared_link": "Nepodařilo se upravit sdílený odkaz",
|
||||
"failed_to_get_people": "Nepodařilo se načíst lidi",
|
||||
"failed_to_keep_this_delete_others": "Nepodařilo se zachovat tuto položku a odstranit ostatní položky",
|
||||
"failed_to_load_asset": "Nepodařilo se načíst položku",
|
||||
"failed_to_load_assets": "Nepodařilo se načíst položky",
|
||||
"failed_to_load_people": "Chyba načítání osob",
|
||||
@@ -656,8 +634,6 @@
|
||||
"unable_to_change_location": "Nelze změnit polohu",
|
||||
"unable_to_change_password": "Nelze změnit heslo",
|
||||
"unable_to_change_visibility": "Nelze změnit viditelnost u {count, plural, one {# osoby} few {# osob} other {# lidí}}",
|
||||
"unable_to_check_item": "Nelze zkontrolovat položku",
|
||||
"unable_to_check_items": "Nelze zkontrolovat položky",
|
||||
"unable_to_complete_oauth_login": "Nelze dokončit OAuth přihlášení",
|
||||
"unable_to_connect": "Nelze se připojit",
|
||||
"unable_to_connect_to_server": "Nepodařilo se připojit k serveru",
|
||||
@@ -698,12 +674,10 @@
|
||||
"unable_to_remove_album_users": "Nelze odebrat uživatele z alba",
|
||||
"unable_to_remove_api_key": "Nelze odstranit API klíč",
|
||||
"unable_to_remove_assets_from_shared_link": "Nelze odstranit položky ze sdíleného odkazu",
|
||||
"unable_to_remove_comment": "Nelze odstranit komentář",
|
||||
"unable_to_remove_deleted_assets": "Nelze odstranit offline soubory",
|
||||
"unable_to_remove_library": "Nelze odstranit knihovnu",
|
||||
"unable_to_remove_partner": "Nelze odebrat partnera",
|
||||
"unable_to_remove_reaction": "Nelze odstranit reakci",
|
||||
"unable_to_remove_user": "Nelze odebrat uživatele",
|
||||
"unable_to_repair_items": "Nelze opravit položky",
|
||||
"unable_to_reset_password": "Nelze obnovit heslo",
|
||||
"unable_to_resolve_duplicate": "Nelze vyřešit duplicitu",
|
||||
@@ -733,10 +707,6 @@
|
||||
"unable_to_update_user": "Nelze aktualizovat uživatele",
|
||||
"unable_to_upload_file": "Nepodařilo se nahrát soubor"
|
||||
},
|
||||
"every_day_at_onepm": "Každý den ve 13:00",
|
||||
"every_night_at_midnight": "Každý den o půlnoci",
|
||||
"every_night_at_twoam": "Každou noc ve 2:00",
|
||||
"every_six_hours": "Každých 6 hodin",
|
||||
"exif": "Exif",
|
||||
"exit_slideshow": "Ukončit prezentaci",
|
||||
"expand_all": "Rozbalit vše",
|
||||
@@ -751,33 +721,27 @@
|
||||
"external": "Externí",
|
||||
"external_libraries": "Externí knihovny",
|
||||
"face_unassigned": "Nepřiřazena",
|
||||
"failed_to_get_people": "Nepodařilo se načíst lidi",
|
||||
"favorite": "Oblíbit",
|
||||
"favorite_or_unfavorite_photo": "Oblíbit nebo zrušit oblíbení fotky",
|
||||
"favorites": "Oblíbené",
|
||||
"feature": "Funkce",
|
||||
"feature_photo_updated": "Hlavní fotka aktualizována",
|
||||
"featurecollection": "Kolekce Funkcí",
|
||||
"features": "Funkce",
|
||||
"features_setting_description": "Správa funkcí aplikace",
|
||||
"file_name": "Název souboru",
|
||||
"file_name_or_extension": "Název nebo přípona souboru",
|
||||
"filename": "Filename",
|
||||
"files": "",
|
||||
"filetype": "Filetype",
|
||||
"filter_people": "Filtrovat lidi",
|
||||
"find_them_fast": "Najděte je rychle vyhledáním jejich jména",
|
||||
"fix_incorrect_match": "Opravit nesprávnou shodu",
|
||||
"folders": "Složky",
|
||||
"folders_feature_description": "Procházení zobrazení složek s fotografiemi a videi v souborovém systému",
|
||||
"force_re-scan_library_files": "Vynucené prohledání všech souborů knihovny",
|
||||
"forward": "Dopředu",
|
||||
"general": "Obecné",
|
||||
"get_help": "Získat pomoc",
|
||||
"getting_started": "Začínáme",
|
||||
"go_back": "Přejít zpět",
|
||||
"go_to_search": "Přejít na vyhledávání",
|
||||
"go_to_share_page": "Přejít na stránku sdílení",
|
||||
"group_albums_by": "Seskupit alba podle...",
|
||||
"group_no": "Neseskupovat",
|
||||
"group_owner": "Seskupit podle uživatele",
|
||||
@@ -803,10 +767,6 @@
|
||||
"image_alt_text_date_place_2_people": "{isVideo, select, true {Video pořízeno} other {Obrázek požízen}} {date} v místě {city}, {country} uživateli {person1} a {person2}",
|
||||
"image_alt_text_date_place_3_people": "{isVideo, select, true {Video pořízeno} other {Obrázek požízen}} {date} v místě {city}, {country} uživateli {person1}, {person2} a {person3}",
|
||||
"image_alt_text_date_place_4_or_more_people": "{isVideo, select, true {Video pořízeno} other {Obrázek požízen}} {date} v místě {city}, {country} uživateli {person1}, {person2} a {additionalCount, plural, one {dalším # uživatelem} other {dalšími # uživateli}}",
|
||||
"image_alt_text_people": "{count, plural, =1 {a {person1}} =2 {s {person1} a {person2}} =3 {s {person1}, {person2}, a {person3}} other {s {person1}, {person2}, a {others, number} dalšími}}",
|
||||
"image_alt_text_place": "v {city}, {country}",
|
||||
"image_taken": "{isVideo, select, true {Video pořízeno} other {Obrázek požízen}}",
|
||||
"img": "Img",
|
||||
"immich_logo": "Immich Logo",
|
||||
"immich_web_interface": "Webové rozhraní Immich",
|
||||
"import_from_json": "Import z JSONu",
|
||||
@@ -827,10 +787,11 @@
|
||||
"invite_people": "Pozvat lidi",
|
||||
"invite_to_album": "Pozvat do alba",
|
||||
"items_count": "{count, plural, one {# položka} few {# položky} other {# položek}}",
|
||||
"job_settings_description": "Správa souběhu úloh",
|
||||
"jobs": "Úlohy",
|
||||
"keep": "Ponechat",
|
||||
"keep_all": "Ponechat vše",
|
||||
"keep_this_delete_others": "Ponechat tuto, odstranit ostatní",
|
||||
"kept_this_deleted_others": "Ponechána tato položka a {count, plural, one {odstraněna # položka} few {odstraněny # položky} other {odstraněno # položek}}",
|
||||
"keyboard_shortcuts": "Klávesové zkratky",
|
||||
"language": "Jazyk",
|
||||
"language_setting_description": "Vyberte upřednostňovaný jazyk",
|
||||
@@ -842,31 +803,6 @@
|
||||
"level": "Úroveň",
|
||||
"library": "Knihovna",
|
||||
"library_options": "Možnosti knihovny",
|
||||
"license_account_info": "Váš účet je licencován",
|
||||
"license_activated_subtitle": "Děkujeme vám za podporu aplikace Immich a open-source softwaru",
|
||||
"license_activated_title": "Vaše licence byla úspěšně aktivována",
|
||||
"license_button_activate": "Aktivovat",
|
||||
"license_button_buy": "Koupit",
|
||||
"license_button_buy_license": "Koupit licenci",
|
||||
"license_button_select": "Vybrat",
|
||||
"license_failed_activation": "Nepodařilo se aktivovat licenci. Zkontrolujte prosím svůj e-mail pro správný licenční klíč!",
|
||||
"license_individual_description_1": "1 licence za uživatele na libovolném serveru",
|
||||
"license_individual_title": "Individuální licence",
|
||||
"license_info_licensed": "Licencováno",
|
||||
"license_info_unlicensed": "Nelicencováno",
|
||||
"license_input_suggestion": "Máte licenci? Zadejte klíč níže",
|
||||
"license_license_subtitle": "Koupí licence podpoříte Immich",
|
||||
"license_license_title": "LICENCE",
|
||||
"license_lifetime_description": "Doživotní licence",
|
||||
"license_per_server": "Za server",
|
||||
"license_per_user": "Za uživatele",
|
||||
"license_server_description_1": "1 licence za každý server",
|
||||
"license_server_description_2": "Licence za všechny uživatele na serveru",
|
||||
"license_server_title": "Serverová licence",
|
||||
"license_trial_info_1": "Používáte nelicencovanou verzi aplikace Immich",
|
||||
"license_trial_info_2": "Immich používáte přibližně",
|
||||
"license_trial_info_3": "{accountAge, plural, one {# den} few {# dny} other {# dní}}",
|
||||
"license_trial_info_4": "Zvažte prosím zakoupení licence na podporu dalšího rozvoje služby",
|
||||
"light": "Světlý",
|
||||
"like_deleted": "Lajk smazán",
|
||||
"link_motion_video": "Připojit pohyblivé video",
|
||||
@@ -888,6 +824,7 @@
|
||||
"look": "Zobrazení",
|
||||
"loop_videos": "Videa ve smyčce",
|
||||
"loop_videos_description": "Povolit automatickou smyčku videa v prohlížeči.",
|
||||
"main_branch_warning": "Používáte vývojovou verzi; důrazně doporučujeme používat verzi z vydání!",
|
||||
"make": "Výrobce",
|
||||
"manage_shared_links": "Spravovat sdílené odkazy",
|
||||
"manage_sharing_with_partners": "Správa sdílení s partnery",
|
||||
@@ -965,13 +902,11 @@
|
||||
"oldest_first": "Nejstarší první",
|
||||
"onboarding": "Zahájení",
|
||||
"onboarding_privacy_description": "Následující (volitelné) funkce jsou závislé na externích službách a lze je kdykoli zakázat v nastavení správy.",
|
||||
"onboarding_storage_template_description": "Pokud je tato funkce povolena, automaticky uspořádá soubory na základě uživatelem definované šablony. Vzhledem k problémům se stabilitou byla tato funkce ve výchozím nastavení vypnuta. Další informace naleznete v [dokumentaci].",
|
||||
"onboarding_theme_description": "Zvolte si barevné téma pro svou instanci. Můžete to později změnit v nastavení.",
|
||||
"onboarding_welcome_description": "Nastavíme vaši instanci pomocí několika běžných nastavení.",
|
||||
"onboarding_welcome_user": "Vítej, {user}",
|
||||
"online": "Online",
|
||||
"only_favorites": "Pouze oblíbené",
|
||||
"only_refreshes_modified_files": "Obnovuje pouze změněné soubory",
|
||||
"open_in_map_view": "Otevřít v zobrazení mapy",
|
||||
"open_in_openstreetmap": "Otevřít v OpenStreetMap",
|
||||
"open_the_search_filters": "Otevřít vyhledávací filtry",
|
||||
@@ -988,7 +923,7 @@
|
||||
"partner_can_access": "{partner} má přístup",
|
||||
"partner_can_access_assets": "Všechny vaše fotky a videa kromě těch, které jsou v sekcích Archivováno a Smazáno",
|
||||
"partner_can_access_location": "Místo, kde byly vaše fotografie pořízeny",
|
||||
"partner_sharing": "Sdílení partnerů",
|
||||
"partner_sharing": "Sdílení mezi partnery",
|
||||
"partners": "Partneři",
|
||||
"password": "Heslo",
|
||||
"password_does_not_match": "Heslo se neshoduje",
|
||||
@@ -1009,14 +944,12 @@
|
||||
"people_edits_count": "Upraveno {count, plural, one {# osoba} few {# osoby} other {# lidí}}",
|
||||
"people_feature_description": "Procházení fotografií a videí seskupených podle osob",
|
||||
"people_sidebar_description": "Zobrazit sekci Lidé v postranním panelu",
|
||||
"perform_library_tasks": "",
|
||||
"permanent_deletion_warning": "Upozornění na trvalé smazání",
|
||||
"permanent_deletion_warning_setting_description": "Zobrazit varování při trvalém odstranění položek",
|
||||
"permanently_delete": "Trvale odstranit",
|
||||
"permanently_delete_assets_count": "Trvale vymazat {count, plural, one {položku} other {položky}}",
|
||||
"permanently_delete_assets_count": "Trvale smazat {count, plural, one {položku} other {položky}}",
|
||||
"permanently_delete_assets_prompt": "Opravdu chcete trvale smazat {count, plural, one {tuto položku} few {tyto <b>#</b> položky} other {těchto <b>#</b> položek}}? Tím {count, plural, one {ji také odstraníte z jejích} other {je také odstraníte z jejich}} alb.",
|
||||
"permanently_deleted_asset": "Položka trvale odstraněna",
|
||||
"permanently_deleted_assets": "Trvale {count, plural, one {odstraněna # položka} few {odstraněny # položky} other {odstraněno # položek}}",
|
||||
"permanently_deleted_assets_count": "{count, plural, one {Položka trvale vymazána} other {Položky trvale vymazány}}",
|
||||
"person": "Osoba",
|
||||
"person_hidden": "{name}{hidden, select, true { (skryto)} other {}}",
|
||||
@@ -1032,7 +965,6 @@
|
||||
"play_memories": "Přehrát vzpomníky",
|
||||
"play_motion_photo": "Přehrát pohybovou fotografii",
|
||||
"play_or_pause_video": "Přehrát nebo pozastavit video",
|
||||
"point": "Bod",
|
||||
"port": "Port",
|
||||
"preset": "Přednastavení",
|
||||
"preview": "Náhled",
|
||||
@@ -1056,19 +988,19 @@
|
||||
"purchase_button_reminder": "Připomenout za 30 dní",
|
||||
"purchase_button_remove_key": "Odstranit klíč",
|
||||
"purchase_button_select": "Vybrat",
|
||||
"purchase_failed_activation": "Aktivace se nezdařila! Zkontrolujte prosím svůj e-mail pro správný produktový klíč!",
|
||||
"purchase_failed_activation": "Aktivace se nezdařila! Zkontrolujte prosím svůj e-mail zda je zadaný produktový klíč bez chyb!",
|
||||
"purchase_individual_description_1": "Pro jednotlivce",
|
||||
"purchase_individual_description_2": "Stav podporovatele",
|
||||
"purchase_individual_title": "Individuální",
|
||||
"purchase_input_suggestion": "Máte produktový klíč? Zadejte klíč níže",
|
||||
"purchase_license_subtitle": "Koupit Immich na podporu dalšího rozvoje služby",
|
||||
"purchase_input_suggestion": "Máte produktový klíč? Zadejte ho níže",
|
||||
"purchase_license_subtitle": "Koupit Immich a podpořit další rozvoj služby",
|
||||
"purchase_lifetime_description": "Doživotní platnost",
|
||||
"purchase_option_title": "MOŽNOSTI NÁKUPU",
|
||||
"purchase_option_title": "MOŽNOSTI ZAKOUPENÍ",
|
||||
"purchase_panel_info_1": "Tvorba aplikace Immich vyžaduje spoustu času a úsilí, a proto na ní pracují vývojáři na plný úvazek, aby byla co nejlepší. Naším cílem je, aby se software s otevřeným zdrojovým kódem a etické obchodní postupy staly udržitelným zdrojem příjmů pro vývojáře a aby vznikl ekosystém respektující soukromí se skutečnými alternativami k ziskuchtivým službám.",
|
||||
"purchase_panel_info_2": "Protože jsme se zavázali, že nebudeme zavádět paywally, nezískáte tímto nákupem žádné další funkce v aplikaci Immich. Spoléháme na uživatele, jako jste vy, že podpoří neustálý vývoj aplikace.",
|
||||
"purchase_panel_title": "Podpora projektu",
|
||||
"purchase_per_server": "Na server",
|
||||
"purchase_per_user": "Na uživatele",
|
||||
"purchase_panel_title": "Podpořit projekt",
|
||||
"purchase_per_server": "Za server",
|
||||
"purchase_per_user": "Za uživatele",
|
||||
"purchase_remove_product_key": "Odstranění produktového klíče",
|
||||
"purchase_remove_product_key_prompt": "Opravdu chcete odebrat produktový klíč?",
|
||||
"purchase_remove_server_product_key": "Odstranění serverového produktového klíče",
|
||||
@@ -1077,12 +1009,10 @@
|
||||
"purchase_server_description_2": "Stav podporovatele",
|
||||
"purchase_server_title": "Server",
|
||||
"purchase_settings_server_activated": "Produktový klíč serveru spravuje správce",
|
||||
"range": "Rozsah",
|
||||
"rating": "Hodnocení hvězdičkami",
|
||||
"rating_clear": "Vyčistit hodnocení",
|
||||
"rating_count": "{count, plural, one {# hvězdička} few {# hvězdičky} other {# hvězdček}}",
|
||||
"rating_description": "Zobrazit EXIF hodnocení v informačním panelu",
|
||||
"raw": "Raw",
|
||||
"reaction_options": "Možnosti reakce",
|
||||
"read_changelog": "Přečtěte si seznam změn",
|
||||
"reassign": "Přeřadit",
|
||||
@@ -1093,11 +1023,13 @@
|
||||
"recent_searches": "Nedávná vyhledávání",
|
||||
"refresh": "Obnovit",
|
||||
"refresh_encoded_videos": "Obnovit kódovaná videa",
|
||||
"refresh_faces": "Obnovit obličeje",
|
||||
"refresh_metadata": "Obnovit metadata",
|
||||
"refresh_thumbnails": "Obnovit miniatury",
|
||||
"refreshed": "Obnoveno",
|
||||
"refreshes_every_file": "Znovu načte všechny stávající a nové soubory",
|
||||
"refreshing_encoded_video": "Obnovování kódovaného videa",
|
||||
"refreshing_faces": "Obnovování obličejů",
|
||||
"refreshing_metadata": "Obnovování metadat",
|
||||
"regenerating_thumbnails": "Regenerace miniatur",
|
||||
"remove": "Odstranit",
|
||||
@@ -1125,7 +1057,6 @@
|
||||
"reset": "Výchozí",
|
||||
"reset_password": "Obnovit heslo",
|
||||
"reset_people_visibility": "Obnovit viditelnost lidí",
|
||||
"reset_settings_to_default": "Obnovit výchozí nastavení",
|
||||
"reset_to_default": "Obnovit výchozí nastavení",
|
||||
"resolve_duplicates": "Vyřešit duplicity",
|
||||
"resolved_all_duplicates": "Vyřešeny všechny duplicity",
|
||||
@@ -1145,9 +1076,7 @@
|
||||
"saved_settings": "Nastavení uloženo",
|
||||
"say_something": "Řekněte něco",
|
||||
"scan_all_libraries": "Prohledat všechny knihovny",
|
||||
"scan_all_library_files": "Prohledání všech souborů knihovny",
|
||||
"scan_library": "Prohledat",
|
||||
"scan_new_library_files": "Hledat nové soubory v knihovně",
|
||||
"scan_settings": "Nastavení prohledávání",
|
||||
"scanning_for_album": "Prohledávání alba...",
|
||||
"search": "Hledat",
|
||||
@@ -1190,9 +1119,8 @@
|
||||
"selected_count": "{count, plural, one {# vybraný} few {# vybrané} other {# vybraných}}",
|
||||
"send_message": "Odeslat zprávu",
|
||||
"send_welcome_email": "Poslat uvítací e-mail",
|
||||
"server": "Server",
|
||||
"server_offline": "Server Offline",
|
||||
"server_online": "Server Online",
|
||||
"server_offline": "Server offline",
|
||||
"server_online": "Server online",
|
||||
"server_stats": "Statistiky serveru",
|
||||
"server_version": "Verze serveru",
|
||||
"set": "Nastavit",
|
||||
@@ -1205,8 +1133,8 @@
|
||||
"settings_saved": "Nastavení uloženo",
|
||||
"share": "Sdílet",
|
||||
"shared": "Sdílené",
|
||||
"shared_by": "Sdílel",
|
||||
"shared_by_user": "Sdíleno uživatelem {user}",
|
||||
"shared_by": "Sdílel(a)",
|
||||
"shared_by_user": "Sdílel(a) {user}",
|
||||
"shared_by_you": "Sdíleli jste",
|
||||
"shared_from_partner": "Fotky od {partner}",
|
||||
"shared_link_options": "Možnosti sdíleného odkazu",
|
||||
@@ -1301,11 +1229,9 @@
|
||||
"to_favorite": "Oblíbit",
|
||||
"to_login": "Přihlásit",
|
||||
"to_parent": "Přejít k rodiči",
|
||||
"to_root": "Přejít ke kořenu",
|
||||
"to_trash": "Vyhodit",
|
||||
"toggle_settings": "Přepnout nastavení",
|
||||
"toggle_theme": "Přepnout tmavý motiv",
|
||||
"toggle_visibility": "Přepnout viditelnost",
|
||||
"total_usage": "Celkové využití",
|
||||
"trash": "Koš",
|
||||
"trash_all": "Vyhodit vše",
|
||||
@@ -1315,12 +1241,10 @@
|
||||
"trashed_items_will_be_permanently_deleted_after": "Smazané položky budou trvale odstraněny po {days, plural, one {# dni} other {# dnech}}.",
|
||||
"type": "Typ",
|
||||
"unarchive": "Odarchivovat",
|
||||
"unarchived": "Odarchivováno",
|
||||
"unarchived_count": "{count, plural, one {Odarchivována #} few {Odarchivovány #} other {Odarchivováno #}}",
|
||||
"unfavorite": "Zrušit oblíbení",
|
||||
"unhide_person": "Zrušit skrytí osoby",
|
||||
"unknown": "Neznámý",
|
||||
"unknown_album": "Neznámé album",
|
||||
"unknown_year": "Neznámý rok",
|
||||
"unlimited": "Neomezeně",
|
||||
"unlink_motion_video": "Odpojit pohyblivé video",
|
||||
@@ -1328,7 +1252,7 @@
|
||||
"unlinked_oauth_account": "OAuth účet odpojen",
|
||||
"unnamed_album": "Nepojmenované album",
|
||||
"unnamed_album_delete_confirmation": "Opravdu chcete toto album smazat?",
|
||||
"unnamed_share": "Nejmenované sdílení",
|
||||
"unnamed_share": "Nepojmenované sdílení",
|
||||
"unsaved_change": "Neuložená změna",
|
||||
"unselect_all": "Zrušit výběr všech",
|
||||
"unselect_all_duplicates": "Zrušit výběr všech duplicit",
|
||||
@@ -1352,8 +1276,6 @@
|
||||
"use_custom_date_range": "Použít vlastní rozsah dat",
|
||||
"user": "Uživatel",
|
||||
"user_id": "ID uživatele",
|
||||
"user_license_settings": "Licence",
|
||||
"user_license_settings_description": "Správa licence",
|
||||
"user_liked": "Uživateli {user} se {type, select, photo {líbila tato fotka} video {líbilo toto video} asset {líbila tato položka} other {to líbilo}}",
|
||||
"user_purchase_settings": "Nákup",
|
||||
"user_purchase_settings_description": "Správa vašeho nákupu",
|
||||
@@ -1366,7 +1288,7 @@
|
||||
"variables": "Proměnné",
|
||||
"version": "Verze",
|
||||
"version_announcement_closing": "Váš přítel Alex",
|
||||
"version_announcement_message": "Ahoj příteli, je tu nová verze aplikace, věnuj prosím čas přečtení <link>poznámek k vydání</link> a zajisti si, aby <code>docker-compose.yml</code> a nastavení <code>.env</code> bylo aktuální, a aby nedošlo k chybné konfiguraci, zejména pokud používáš WatchTower nebo jiný mechanismus, který se stará o automatickou aktualizaci aplikace.",
|
||||
"version_announcement_message": "Ahoj! K dispozici je nová verze aplikace Immich. Věnujte prosím chvíli přečtení <link>poznámek k vydání</link> a ujistěte se, že je vaše nastavení aktuální, abyste předešli případným chybným konfiguracím, zejména pokud používáte WatchTower nebo jiný mechanismus, který se stará o automatickou aktualizaci instance aplikace Immich.",
|
||||
"version_history": "Historie verzí",
|
||||
"version_history_item": "Nainstalováno {version} dne {date}",
|
||||
"video": "Video",
|
||||
@@ -1383,7 +1305,6 @@
|
||||
"view_next_asset": "Zobrazit další položku",
|
||||
"view_previous_asset": "Zobrazit předchozí položku",
|
||||
"view_stack": "Zobrazit seskupení",
|
||||
"viewer": "Prohlížeč",
|
||||
"visibility_changed": "Viditelnost změněna u {count, plural, one {# osoby} few {# osob} other {# lidí}}",
|
||||
"waiting": "Čekající",
|
||||
"warning": "Upozornění",
|
||||
49
i18n/cv.json
Normal file
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"about": "Ҫинчен",
|
||||
"account": "Шута ҫырни",
|
||||
"account_settings": "Шута ҫырни ӗнерленӳ",
|
||||
"acknowledge": "Çирӗплет",
|
||||
"action": "Ӗçлени",
|
||||
"actions": "Ӗҫсем",
|
||||
"active": "Хастар",
|
||||
"activity": "Хастарлӑх",
|
||||
"activity_changed": "Хастарлӑха {enabled, select, true {кӗртнӗ} other {сӳнтернӗ}}",
|
||||
"add": "Хуш",
|
||||
"add_a_description": "Ҫырса кӑтартни хуш",
|
||||
"add_a_location": "Вырӑн хуш",
|
||||
"add_a_name": "Ятне хуш",
|
||||
"add_a_title": "Ят хуш",
|
||||
"add_exclusion_pattern": "Кӑларса пӑрахмалли йӗрке хуш",
|
||||
"add_import_path": "Импорт ҫулне хуш",
|
||||
"add_location": "Вырӑн хуш",
|
||||
"add_more_users": "Усӑҫсем ытларах хуш",
|
||||
"add_partner": "Мӑшӑр хуш",
|
||||
"add_path": "Ҫулне хуш",
|
||||
"add_photos": "Сӑнӳкерчӗксем хуш",
|
||||
"add_to": "Мӗн те пулин хуш...",
|
||||
"add_to_album": "Альбома хуш",
|
||||
"add_to_shared_album": "Пӗрлехи альбома хуш",
|
||||
"added_to_archive": "Архива хушнӑ",
|
||||
"added_to_favorites": "Суйласа илнине хушнӑ",
|
||||
"added_to_favorites_count": "Суйласа илнине {count, number} хушнӑ",
|
||||
"admin": {
|
||||
"asset_offline_description": "Библиотекӑн ҫак тулаш файлне дискра урӑх тупайман, карҫинккана куҫарнӑ. Енчен те файла вулавӑш ӑшне куҫарнӑ пулсан, тивӗҫлӗ ҫӗнӗ ресурс тупас тесен хӑвӑрӑн вӑхӑтлӑх шкалӑна тӗрӗслӗр. Ҫак файла ҫӗнӗрен чӗртес тесен файл патне каймалли ҫула Immich валли аяларах ҫитернине курса ӗненӗр, библиотекӑна сканерланине пурнӑҫлӑр.",
|
||||
"authentication_settings_disable_all": "Эсир кӗмелли пур меслетсене те чарса лартасшӑн тесе шутлатӑр-и? Кӗмелли шӑтӑка пӗтӗмпех уҫаҫҫӗ.",
|
||||
"background_task_job": "Курăнман ӗҫсем",
|
||||
"check_all": "Пурне те тӗрӗслӗр",
|
||||
"cleared_jobs": "Ӗҫсене тасатнӑ:{job}",
|
||||
"confirm_email_below": "Ҫирӗплетес тесен, аяларах «{email}» кӗртӗр",
|
||||
"confirm_reprocess_all_faces": "Пӗтӗм сӑнӗсене тепӗр хут палӑртас килет тесе шанатӑр-и? Ҫавӑн пекех ятсене пур ҫынран та хуратӗҫ.",
|
||||
"create_job": "Ӗҫе ту",
|
||||
"disable_login": "Кӗме чарӑр",
|
||||
"duplicate_detection_job_description": "Пӗр пек ӳкерчӗксене тупма машинӑллӑ вӗренӗве ӗҫлеттерӗр. Ӑслӑ шыравпа усӑ кураҫҫӗ",
|
||||
"face_detection": "Пит-куҫа тупасси",
|
||||
"force_delete_user_warning": "ПУЛТАРУЛӐХ: Ку усӑ куракана тата мӗнпур ресурса ҫийӗнчех кӑларса пӑрахасси патне илсе ҫитерӗ. Кӑна пӑрахӑҫлама май ҫук, файлсене те юсаса пӗтереймеҫҫӗ.",
|
||||
"image_format": "Тулашлăх",
|
||||
"image_preview_description": "Вӑтам пысӑкӑш ӳкерчӗк, уйрӑм метаданнӑйсем, пӗр объекта пӑхнӑ чухне тата машинӑллӑ вӗренӳре усӑ кураҫҫӗ",
|
||||
"image_preview_quality_description": "1-100 таран малтанхи пахалӑх. Ҫӳллӗреххи лайӑхрах, анчах та пысӑкрах файлсем туса кӑларать тата приложенисен хуравлӑхне чакарма пултарать. Пӗчӗк хак лартни машинӑллӑ вӗренӳ пахалӑхне витӗм кӳме пултарать.",
|
||||
"image_preview_title": "Малтанлӑха пӑхмалли ӗнерлевсем",
|
||||
"image_quality": "Пахалӑх",
|
||||
"image_resolution": "Виҫе"
|
||||
}
|
||||
}
|
||||