mirror of
https://github.com/immich-app/immich.git
synced 2025-12-07 13:21:02 -08:00
Compare commits
164 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
96f29cefeb | ||
|
|
6f950ea45d | ||
|
|
99c45bd4d2 | ||
|
|
312030f275 | ||
|
|
bed9ccadbc | ||
|
|
d55499eba0 | ||
|
|
910b75c6cc | ||
|
|
6a11464d60 | ||
|
|
aa29f5d69c | ||
|
|
1ee10ee2d6 | ||
|
|
f23401d911 | ||
|
|
14d94df1b8 | ||
|
|
b47ec2f88f | ||
|
|
b5c8ca075c | ||
|
|
7bfa642fa3 | ||
|
|
9a83038728 | ||
|
|
a1629f0793 | ||
|
|
d4cba57102 | ||
|
|
2934676594 | ||
|
|
ebea793534 | ||
|
|
eeae77422f | ||
|
|
850424e960 | ||
|
|
58298bd038 | ||
|
|
e46af5c26b | ||
|
|
3b37b70626 | ||
|
|
4193b0dede | ||
|
|
ac51cad075 | ||
|
|
b54dd4e135 | ||
|
|
f5164b42e0 | ||
|
|
783088afbe | ||
|
|
744dfb675b | ||
|
|
1d282851e2 | ||
|
|
d00d33d8a5 | ||
|
|
560dbd3c65 | ||
|
|
c58148af35 | ||
|
|
e54c18367b | ||
|
|
8b6d27f1bc | ||
|
|
887acb9d9f | ||
|
|
8f553ddb39 | ||
|
|
24c1855899 | ||
|
|
6ebae3c84f | ||
|
|
e0bb9add91 | ||
|
|
821570f2fb | ||
|
|
a2364a12cf | ||
|
|
e361640e39 | ||
|
|
37b5d92110 | ||
|
|
325aa1d392 | ||
|
|
72bf9439b0 | ||
|
|
7e99394c70 | ||
|
|
8ff9c37d79 | ||
|
|
0b4153e256 | ||
|
|
12b9f3ad91 | ||
|
|
9fc9465cec | ||
|
|
d8175d8da8 | ||
|
|
922430da36 | ||
|
|
a3c3619811 | ||
|
|
7f5a3e5adb | ||
|
|
63041674c2 | ||
|
|
8a445cac07 | ||
|
|
15c1cd6449 | ||
|
|
8198259de8 | ||
|
|
6decf33226 | ||
|
|
df0064c83b | ||
|
|
c754f2504b | ||
|
|
0891658668 | ||
|
|
5b909eeaf0 | ||
|
|
0484a4e252 | ||
|
|
bf83fdee49 | ||
|
|
9eafbb0524 | ||
|
|
6356c28f64 | ||
|
|
6538ad8de7 | ||
|
|
9f9e42a96a | ||
|
|
905d6c1508 | ||
|
|
91af793b52 | ||
|
|
5912fcc393 | ||
|
|
b5b0c6fe8b | ||
|
|
330648ff44 | ||
|
|
54d1dc56a2 | ||
|
|
d8e6b17ef9 | ||
|
|
d7a33c8ec2 | ||
|
|
0012369c67 | ||
|
|
cb3ac4ff9f | ||
|
|
4988df3fcb | ||
|
|
fc6c9a19d9 | ||
|
|
13cc1f0aa6 | ||
|
|
ba72802888 | ||
|
|
04f0e29df6 | ||
|
|
c83de5213f | ||
|
|
dd2c7400a6 | ||
|
|
df9e074304 | ||
|
|
5f47cf604a | ||
|
|
8e2f6f1f41 | ||
|
|
32da9d90e4 | ||
|
|
6164640575 | ||
|
|
4cb165304b | ||
|
|
1200265425 | ||
|
|
0a3aafd439 | ||
|
|
aaf7c0b6db | ||
|
|
b3252ffdac | ||
|
|
1129020159 | ||
|
|
61a5d67674 | ||
|
|
42f3b50422 | ||
|
|
5e9a7b17d9 | ||
|
|
0fda67543d | ||
|
|
5cde52eec9 | ||
|
|
eff839251c | ||
|
|
a42af06889 | ||
|
|
79a8ab71ef | ||
|
|
1191978d50 | ||
|
|
7ea0278b32 | ||
|
|
4ef033aa55 | ||
|
|
660afa9fad | ||
|
|
104048ecd5 | ||
|
|
bec77f926e | ||
|
|
ba57a1144d | ||
|
|
b3f9641edf | ||
|
|
86cbc6e125 | ||
|
|
968553a50e | ||
|
|
5813dc02d1 | ||
|
|
58b17a866b | ||
|
|
c58b0ac66a | ||
|
|
517a83cfa9 | ||
|
|
7daa761eed | ||
|
|
e58131492d | ||
|
|
b21572cb32 | ||
|
|
8332efcd04 | ||
|
|
b71aa4473b | ||
|
|
99c6fdbc1c | ||
|
|
c1a5ed3526 | ||
|
|
9000ce4283 | ||
|
|
e8994d9ffd | ||
|
|
1b67ea2d91 | ||
|
|
38e26fd67c | ||
|
|
29e4666dfa | ||
|
|
7ce87abc95 | ||
|
|
eb987c14c1 | ||
|
|
a6e767e46d | ||
|
|
8e373cee8d | ||
|
|
6b1b5054f8 | ||
|
|
0fe152b1ef | ||
|
|
e77e87b936 | ||
|
|
0b08af7082 | ||
|
|
010eb1e0d6 | ||
|
|
83a851b556 | ||
|
|
1cd51cc2de | ||
|
|
f3c15c7df8 | ||
|
|
6a5435764e | ||
|
|
dfad4f0ff4 | ||
|
|
aea1c46bea | ||
|
|
78f600ebce | ||
|
|
c896fe393f | ||
|
|
b4b654b53f | ||
|
|
dddc06c3b2 | ||
|
|
596412cb8f | ||
|
|
e3a314b649 | ||
|
|
2bdb4bca9e | ||
|
|
211451d234 | ||
|
|
e1731fe316 | ||
|
|
ee186a40c2 | ||
|
|
32a0688028 | ||
|
|
e5ed7d4af1 | ||
|
|
30627fe91e | ||
|
|
77bd162872 | ||
|
|
c6ab047167 |
4
.github/ISSUE_TEMPLATE/config.yml
vendored
4
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,11 +1,11 @@
|
|||||||
blank_issues_enabled: false
|
blank_issues_enabled: false
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: I have a question or need support
|
- name: I have a question or need support
|
||||||
url: https://discord.gg/D8JsnBEuKb
|
url: https://discord.immich.app
|
||||||
about: We use GitHub for tracking bugs, please check out our Discord channel for freaky fast support.
|
about: We use GitHub for tracking bugs, please check out our Discord channel for freaky fast support.
|
||||||
- name: Feature Request
|
- name: Feature Request
|
||||||
url: https://github.com/immich-app/immich/discussions/new?category=feature-request
|
url: https://github.com/immich-app/immich/discussions/new?category=feature-request
|
||||||
about: Please use our GitHub Discussion for making feature requests.
|
about: Please use our GitHub Discussion for making feature requests.
|
||||||
- name: I'm unsure where to go
|
- name: I'm unsure where to go
|
||||||
url: https://discord.gg/D8JsnBEuKb
|
url: https://discord.immich.app
|
||||||
about: If you are unsure where to go, then joining our Discord is recommended; Just ask!
|
about: If you are unsure where to go, then joining our Discord is recommended; Just ask!
|
||||||
|
|||||||
36
.github/labeler.yml
vendored
36
.github/labeler.yml
vendored
@@ -1,23 +1,35 @@
|
|||||||
cli:
|
cli:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file: cli/**
|
- any-glob-to-any-file:
|
||||||
|
- cli/src/**
|
||||||
|
|
||||||
documentation:
|
documentation:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file: docs/**
|
- any-glob-to-any-file:
|
||||||
|
- docs/blob/**
|
||||||
|
- docs/docs/**
|
||||||
|
- docs/src/**
|
||||||
|
- docs/static/**
|
||||||
|
|
||||||
🖥️web:
|
🖥️web:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file: web/**
|
- any-glob-to-any-file:
|
||||||
|
- web/src/**
|
||||||
|
- web/static/**
|
||||||
|
|
||||||
📱mobile:
|
📱mobile:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file: mobile/**
|
- any-glob-to-any-file:
|
||||||
|
- mobile/lib/**
|
||||||
|
- mobile/test/**
|
||||||
|
|
||||||
🗄️server:
|
🗄️server:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file: server/**
|
- any-glob-to-any-file:
|
||||||
|
- server/src/**
|
||||||
|
- server/test/**
|
||||||
|
|
||||||
🧠machine-learning:
|
🧠machine-learning:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file: machine-learning/**
|
- any-glob-to-any-file:
|
||||||
|
- machine-learning/app/**
|
||||||
|
|||||||
4
.github/workflows/cli.yml
vendored
4
.github/workflows/cli.yml
vendored
@@ -33,7 +33,7 @@ jobs:
|
|||||||
# Setup .npmrc file to publish to npm
|
# Setup .npmrc file to publish to npm
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '20.x'
|
node-version-file: './cli/.nvmrc'
|
||||||
registry-url: 'https://registry.npmjs.org'
|
registry-url: 'https://registry.npmjs.org'
|
||||||
- name: Prepare SDK
|
- name: Prepare SDK
|
||||||
run: npm ci --prefix ../open-api/typescript-sdk/
|
run: npm ci --prefix ../open-api/typescript-sdk/
|
||||||
@@ -88,7 +88,7 @@ jobs:
|
|||||||
type=raw,value=latest,enable=${{ github.event_name == 'release' }}
|
type=raw,value=latest,enable=${{ github.event_name == 'release' }}
|
||||||
|
|
||||||
- name: Build and push image
|
- name: Build and push image
|
||||||
uses: docker/build-push-action@v5.4.0
|
uses: docker/build-push-action@v6.2.0
|
||||||
with:
|
with:
|
||||||
file: cli/Dockerfile
|
file: cli/Dockerfile
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
|
|||||||
10
.github/workflows/docker.yml
vendored
10
.github/workflows/docker.yml
vendored
@@ -115,7 +115,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Build and push image
|
- name: Build and push image
|
||||||
uses: docker/build-push-action@v5.4.0
|
uses: docker/build-push-action@v6.2.0
|
||||||
with:
|
with:
|
||||||
context: ${{ matrix.context }}
|
context: ${{ matrix.context }}
|
||||||
file: ${{ matrix.file }}
|
file: ${{ matrix.file }}
|
||||||
@@ -124,7 +124,11 @@ jobs:
|
|||||||
push: ${{ !github.event.pull_request.head.repo.fork }}
|
push: ${{ !github.event.pull_request.head.repo.fork }}
|
||||||
cache-from: type=registry,ref=ghcr.io/${{ github.repository_owner }}/immich-build-cache:${{matrix.image}}
|
cache-from: type=registry,ref=ghcr.io/${{ github.repository_owner }}/immich-build-cache:${{matrix.image}}
|
||||||
cache-to: ${{ steps.cache-target.outputs.cache-to }}
|
cache-to: ${{ steps.cache-target.outputs.cache-to }}
|
||||||
build-args: |
|
|
||||||
DEVICE=${{ matrix.device }}
|
|
||||||
tags: ${{ steps.metadata.outputs.tags }}
|
tags: ${{ steps.metadata.outputs.tags }}
|
||||||
labels: ${{ steps.metadata.outputs.labels }}
|
labels: ${{ steps.metadata.outputs.labels }}
|
||||||
|
build-args: |
|
||||||
|
DEVICE=${{ matrix.device }}
|
||||||
|
BUILD_ID=${{ github.run_id }}
|
||||||
|
BUILD_IMAGE=${{ github.event_name == 'release' && github.ref_name || steps.metadata.outputs.tags }}
|
||||||
|
BUILD_SOURCE_REF=${{ github.ref_name }}
|
||||||
|
BUILD_SOURCE_COMMIT=${{ github.sha }}
|
||||||
|
|||||||
5
.github/workflows/docs-build.yml
vendored
5
.github/workflows/docs-build.yml
vendored
@@ -26,6 +26,11 @@ jobs:
|
|||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version-file: './docs/.nvmrc'
|
||||||
|
|
||||||
- name: Run npm install
|
- name: Run npm install
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/sdk.yml
vendored
2
.github/workflows/sdk.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
|||||||
# Setup .npmrc file to publish to npm
|
# Setup .npmrc file to publish to npm
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '20.x'
|
node-version-file: './open-api/typescript-sdk/.nvmrc'
|
||||||
registry-url: 'https://registry.npmjs.org'
|
registry-url: 'https://registry.npmjs.org'
|
||||||
- name: Install deps
|
- name: Install deps
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|||||||
56
.github/workflows/test.yml
vendored
56
.github/workflows/test.yml
vendored
@@ -21,6 +21,11 @@ jobs:
|
|||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version-file: './server/.nvmrc'
|
||||||
|
|
||||||
- name: Run npm install
|
- name: Run npm install
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
||||||
@@ -54,7 +59,7 @@ jobs:
|
|||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version-file: './cli/.nvmrc'
|
||||||
|
|
||||||
- name: Setup typescript-sdk
|
- name: Setup typescript-sdk
|
||||||
run: npm ci && npm run build
|
run: npm ci && npm run build
|
||||||
@@ -79,6 +84,38 @@ jobs:
|
|||||||
run: npm run test:cov
|
run: npm run test:cov
|
||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
|
|
||||||
|
cli-unit-tests-win:
|
||||||
|
name: CLI (Windows)
|
||||||
|
runs-on: windows-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: ./cli
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version-file: './cli/.nvmrc'
|
||||||
|
|
||||||
|
- name: Setup typescript-sdk
|
||||||
|
run: npm ci && npm run build
|
||||||
|
working-directory: ./open-api/typescript-sdk
|
||||||
|
|
||||||
|
- name: Install deps
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
# Skip linter & formatter in Windows test.
|
||||||
|
- name: Run tsc
|
||||||
|
run: npm run check
|
||||||
|
if: ${{ !cancelled() }}
|
||||||
|
|
||||||
|
- name: Run unit tests & coverage
|
||||||
|
run: npm run test:cov
|
||||||
|
if: ${{ !cancelled() }}
|
||||||
|
|
||||||
web-unit-tests:
|
web-unit-tests:
|
||||||
name: Web
|
name: Web
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -90,6 +127,11 @@ jobs:
|
|||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version-file: './web/.nvmrc'
|
||||||
|
|
||||||
- name: Run setup typescript-sdk
|
- name: Run setup typescript-sdk
|
||||||
run: npm ci && npm run build
|
run: npm ci && npm run build
|
||||||
working-directory: ./open-api/typescript-sdk
|
working-directory: ./open-api/typescript-sdk
|
||||||
@@ -133,7 +175,7 @@ jobs:
|
|||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version-file: './e2e/.nvmrc'
|
||||||
|
|
||||||
- name: Run setup typescript-sdk
|
- name: Run setup typescript-sdk
|
||||||
run: npm ci && npm run build
|
run: npm ci && npm run build
|
||||||
@@ -241,6 +283,11 @@ jobs:
|
|||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version-file: './server/.nvmrc'
|
||||||
|
|
||||||
- name: Install server dependencies
|
- name: Install server dependencies
|
||||||
run: npm --prefix=server ci
|
run: npm --prefix=server ci
|
||||||
|
|
||||||
@@ -291,6 +338,11 @@ jobs:
|
|||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version-file: './server/.nvmrc'
|
||||||
|
|
||||||
- name: Install server dependencies
|
- name: Install server dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
||||||
|
|||||||
9
Makefile
9
Makefile
@@ -36,14 +36,17 @@ sql:
|
|||||||
attach-server:
|
attach-server:
|
||||||
docker exec -it docker_immich-server_1 sh
|
docker exec -it docker_immich-server_1 sh
|
||||||
|
|
||||||
|
renovate:
|
||||||
|
LOG_LEVEL=debug npx renovate --platform=local --repository-cache=reset
|
||||||
|
|
||||||
MODULES = e2e server web cli sdk
|
MODULES = e2e server web cli sdk
|
||||||
|
|
||||||
audit-%:
|
audit-%:
|
||||||
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) audit fix
|
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) audit fix
|
||||||
install-%:
|
install-%:
|
||||||
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) i
|
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) i
|
||||||
build-cli: build-sdk
|
build-cli: build-sdk
|
||||||
build-web: build-sdk
|
build-web: build-sdk
|
||||||
build-%: install-%
|
build-%: install-%
|
||||||
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) run | grep 'build' >/dev/null \
|
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 || true
|
||||||
@@ -73,7 +76,7 @@ audit-all: $(foreach M,$(MODULES),audit-$M) ;
|
|||||||
hygiene-all: lint-all format-all check-all sql audit-all;
|
hygiene-all: lint-all format-all check-all sql audit-all;
|
||||||
test-all: $(foreach M,$(MODULES),test-$M) ;
|
test-all: $(foreach M,$(MODULES),test-$M) ;
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
find . -name "node_modules" -type d -prune -exec rm -rf '{}' +
|
find . -name "node_modules" -type d -prune -exec rm -rf '{}' +
|
||||||
find . -name "dist" -type d -prune -exec rm -rf '{}' +
|
find . -name "dist" -type d -prune -exec rm -rf '{}' +
|
||||||
find . -name "build" -type d -prune -exec rm -rf '{}' +
|
find . -name "build" -type d -prune -exec rm -rf '{}' +
|
||||||
|
|||||||
92
README.md
92
README.md
@@ -1,7 +1,7 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<br/>
|
<br/>
|
||||||
<a href="https://opensource.org/license/agpl-v3"><img src="https://img.shields.io/badge/License-AGPL_v3-blue.svg?color=3F51B5&style=for-the-badge&label=License&logoColor=000000&labelColor=ececec" alt="License: AGPLv3"></a>
|
<a href="https://opensource.org/license/agpl-v3"><img src="https://img.shields.io/badge/License-AGPL_v3-blue.svg?color=3F51B5&style=for-the-badge&label=License&logoColor=000000&labelColor=ececec" alt="License: AGPLv3"></a>
|
||||||
<a href="https://discord.gg/D8JsnBEuKb">
|
<a href="https://discord.immich.app">
|
||||||
<img src="https://img.shields.io/discord/979116623879368755.svg?label=Discord&logo=Discord&style=for-the-badge&logoColor=000000&labelColor=ececec" alt="Discord"/>
|
<img src="https://img.shields.io/discord/979116623879368755.svg?label=Discord&logo=Discord&style=for-the-badge&logoColor=000000&labelColor=ececec" alt="Discord"/>
|
||||||
</a>
|
</a>
|
||||||
<br/>
|
<br/>
|
||||||
@@ -19,20 +19,21 @@
|
|||||||
<br/>
|
<br/>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
|
|
||||||
<a href="readme_i18n/README_ca_ES.md">Català</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_es_ES.md">Español</a>
|
||||||
<a href="readme_i18n/README_fr_FR.md">Français</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_it_IT.md">Italiano</a>
|
||||||
<a href="readme_i18n/README_ja_JP.md">日本語</a>
|
<a href="readme_i18n/README_ja_JP.md">日本語</a>
|
||||||
<a href="readme_i18n/README_ko_KR.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_de_DE.md">Deutsch</a>
|
||||||
<a href="readme_i18n/README_nl_NL.md">Nederlands</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_tr_TR.md">Türkçe</a>
|
||||||
<a href="readme_i18n/README_zh_CN.md">中文</a>
|
<a href="readme_i18n/README_zh_CN.md">中文</a>
|
||||||
<a href="readme_i18n/README_ru_RU.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_pt_BR.md">Português Brasileiro</a>
|
||||||
<a href="readme_i18n/README_sv_SE.md">Svenska</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_ar_JO.md">العربية</a>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
## Disclaimer
|
## Disclaimer
|
||||||
@@ -42,45 +43,36 @@
|
|||||||
- ⚠️ **Do not use the app as the only way to store your photos and videos.**
|
- ⚠️ **Do not use the app as the only way to store your photos and videos.**
|
||||||
- ⚠️ Always follow [3-2-1](https://www.backblaze.com/blog/the-3-2-1-backup-strategy/) backup plan for your precious photos and videos!
|
- ⚠️ Always follow [3-2-1](https://www.backblaze.com/blog/the-3-2-1-backup-strategy/) backup plan for your precious photos and videos!
|
||||||
|
|
||||||
## Content
|
> [!NOTE]
|
||||||
|
> You can find the main documentation, including installation guides, at https://immich.app/.
|
||||||
|
|
||||||
- [Official Documentation](https://immich.app/docs)
|
## Links
|
||||||
- [Roadmap](https://github.com/orgs/immich-app/projects/1)
|
|
||||||
|
- [Documentation](https://immich.app/docs)
|
||||||
|
- [About](https://immich.app/docs/overview/introduction)
|
||||||
|
- [Installation](https://immich.app/docs/install/requirements)
|
||||||
|
- [Roadmap](https://immich.app/roadmap)
|
||||||
- [Demo](#demo)
|
- [Demo](#demo)
|
||||||
- [Features](#features)
|
- [Features](#features)
|
||||||
- [Introduction](https://immich.app/docs/overview/introduction)
|
- [Translations](https://immich.app/docs/developer/translations)
|
||||||
- [Installation](https://immich.app/docs/install/requirements)
|
- [Contributing](https://immich.app/docs/overview/support-the-project)
|
||||||
- [Contribution Guidelines](https://immich.app/docs/overview/support-the-project)
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
You can find the main documentation, including installation guides, at https://immich.app/.
|
|
||||||
|
|
||||||
## Demo
|
## Demo
|
||||||
|
|
||||||
You can access the web demo at https://demo.immich.app
|
Access the demo [here](https://demo.immich.app). The demo is running on a Free-tier Oracle VM in Amsterdam with a 2.4Ghz quad-core ARM64 CPU and 24GB RAM.
|
||||||
|
|
||||||
For the mobile app, you can use `https://demo.immich.app/api` for the `Server Endpoint URL`
|
For the mobile app, you can use `https://demo.immich.app/api` for the `Server Endpoint URL`
|
||||||
|
|
||||||
```bash title="Demo Credential"
|
### Login credentials
|
||||||
The credential
|
|
||||||
email: demo@immich.app
|
|
||||||
password: demo
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
| Email | Password |
|
||||||
Spec: Free-tier Oracle VM - Amsterdam - 2.4Ghz quad-core ARM64 CPU, 24GB RAM
|
| --------------- | -------- |
|
||||||
```
|
| demo@immich.app | demo |
|
||||||
|
|
||||||
## Activities
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
|
|
||||||
| Features | Mobile | Web |
|
| Features | Mobile | Web |
|
||||||
| :--------------------------------------------- | -------- | ----- |
|
| :------------------------------------------- | ------ | --- |
|
||||||
| Upload and view videos and photos | Yes | Yes |
|
| Upload and view videos and photos | Yes | Yes |
|
||||||
| Auto backup when the app is opened | Yes | N/A |
|
| Auto backup when the app is opened | Yes | N/A |
|
||||||
| Prevent duplication of assets | Yes | Yes |
|
| Prevent duplication of assets | Yes | Yes |
|
||||||
@@ -110,13 +102,19 @@ Spec: Free-tier Oracle VM - Amsterdam - 2.4Ghz quad-core ARM64 CPU, 24GB RAM
|
|||||||
| Read-only gallery | Yes | Yes |
|
| Read-only gallery | Yes | Yes |
|
||||||
| Stacked Photos | Yes | Yes |
|
| Stacked Photos | Yes | Yes |
|
||||||
|
|
||||||
## Contributors
|
## Translations
|
||||||
|
|
||||||
<a href="https://github.com/alextran1502/immich/graphs/contributors">
|
Read more about translations [here](https://immich.app/docs/developer/translations).
|
||||||
<img src="https://contrib.rocks/image?repo=immich-app/immich" width="100%"/>
|
|
||||||
|
<a href="https://hosted.weblate.org/engage/immich/">
|
||||||
|
<img src="https://hosted.weblate.org/widget/immich/immich/multi-auto.svg" alt="Translation status" />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
## Star History
|
## Repository activity
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Star history
|
||||||
|
|
||||||
<a href="https://star-history.com/#immich-app/immich&Date">
|
<a href="https://star-history.com/#immich-app/immich&Date">
|
||||||
<picture>
|
<picture>
|
||||||
@@ -125,3 +123,9 @@ Spec: Free-tier Oracle VM - Amsterdam - 2.4Ghz quad-core ARM64 CPU, 24GB RAM
|
|||||||
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=immich-app/immich&type=Date" width="100%" />
|
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=immich-app/immich&type=Date" width="100%" />
|
||||||
</picture>
|
</picture>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
<a href="https://github.com/alextran1502/immich/graphs/contributors">
|
||||||
|
<img src="https://contrib.rocks/image?repo=immich-app/immich" width="100%"/>
|
||||||
|
</a>
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
## Reporting a Vulnerability
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
Please report security issues to `alex.tran1502@gmail.com`
|
Please report security issues to `security@immich.app`
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
20.14
|
20.15
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM node:20-alpine3.19@sha256:696ae41fb5880949a15ade7879a2deae93b3f0723f757bdb5b8a9e4a744ce27f as core
|
FROM node:20.15.0-alpine3.20@sha256:df01469346db2bf1cfc1f7261aeab86b2960efa840fe2bd46d83ff339f463665 as core
|
||||||
|
|
||||||
WORKDIR /usr/src/open-api/typescript-sdk
|
WORKDIR /usr/src/open-api/typescript-sdk
|
||||||
COPY open-api/typescript-sdk/package*.json open-api/typescript-sdk/tsconfig*.json ./
|
COPY open-api/typescript-sdk/package*.json open-api/typescript-sdk/tsconfig*.json ./
|
||||||
@@ -16,4 +16,4 @@ RUN npm run build
|
|||||||
|
|
||||||
WORKDIR /import
|
WORKDIR /import
|
||||||
|
|
||||||
ENTRYPOINT ["node", "/usr/src/app/dist"]
|
ENTRYPOINT ["node", "/usr/src/app/dist"]
|
||||||
|
|||||||
385
cli/package-lock.json
generated
385
cli/package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@immich/cli",
|
"name": "@immich/cli",
|
||||||
"version": "2.2.4",
|
"version": "2.2.7",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@immich/cli",
|
"name": "@immich/cli",
|
||||||
"version": "2.2.4",
|
"version": "2.2.7",
|
||||||
"license": "GNU Affero General Public License version 3",
|
"license": "GNU Affero General Public License version 3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fast-glob": "^3.3.2",
|
"fast-glob": "^3.3.2",
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
"@types/cli-progress": "^3.11.0",
|
"@types/cli-progress": "^3.11.0",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/mock-fs": "^4.13.1",
|
"@types/mock-fs": "^4.13.1",
|
||||||
"@types/node": "^20.3.1",
|
"@types/node": "^20.14.9",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
||||||
"@typescript-eslint/parser": "^7.0.0",
|
"@typescript-eslint/parser": "^7.0.0",
|
||||||
"@vitest/coverage-v8": "^1.2.2",
|
"@vitest/coverage-v8": "^1.2.2",
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
"eslint": "^8.56.0",
|
"eslint": "^8.56.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-prettier": "^5.1.3",
|
"eslint-plugin-prettier": "^5.1.3",
|
||||||
"eslint-plugin-unicorn": "^53.0.0",
|
"eslint-plugin-unicorn": "^54.0.0",
|
||||||
"mock-fs": "^5.2.0",
|
"mock-fs": "^5.2.0",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
"prettier-plugin-organize-imports": "^3.2.4",
|
"prettier-plugin-organize-imports": "^3.2.4",
|
||||||
@@ -47,14 +47,14 @@
|
|||||||
},
|
},
|
||||||
"../open-api/typescript-sdk": {
|
"../open-api/typescript-sdk": {
|
||||||
"name": "@immich/sdk",
|
"name": "@immich/sdk",
|
||||||
"version": "1.106.4",
|
"version": "1.107.2",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "GNU Affero General Public License version 3",
|
"license": "GNU Affero General Public License version 3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@oazapfts/runtime": "^1.0.2"
|
"@oazapfts/runtime": "^1.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^20.11.0",
|
"@types/node": "^20.14.9",
|
||||||
"typescript": "^5.3.3"
|
"typescript": "^5.3.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -300,13 +300,14 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/aix-ppc64": {
|
"node_modules/@esbuild/aix-ppc64": {
|
||||||
"version": "0.20.2",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
|
||||||
"integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==",
|
"integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"aix"
|
"aix"
|
||||||
@@ -316,13 +317,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/android-arm": {
|
"node_modules/@esbuild/android-arm": {
|
||||||
"version": "0.20.2",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
|
||||||
"integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==",
|
"integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"android"
|
"android"
|
||||||
@@ -332,13 +334,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/android-arm64": {
|
"node_modules/@esbuild/android-arm64": {
|
||||||
"version": "0.20.2",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
|
||||||
"integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==",
|
"integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"android"
|
"android"
|
||||||
@@ -348,13 +351,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/android-x64": {
|
"node_modules/@esbuild/android-x64": {
|
||||||
"version": "0.20.2",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
|
||||||
"integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==",
|
"integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"android"
|
"android"
|
||||||
@@ -364,13 +368,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/darwin-arm64": {
|
"node_modules/@esbuild/darwin-arm64": {
|
||||||
"version": "0.20.2",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
|
||||||
"integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==",
|
"integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
@@ -380,13 +385,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/darwin-x64": {
|
"node_modules/@esbuild/darwin-x64": {
|
||||||
"version": "0.20.2",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
|
||||||
"integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==",
|
"integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
@@ -396,13 +402,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/freebsd-arm64": {
|
"node_modules/@esbuild/freebsd-arm64": {
|
||||||
"version": "0.20.2",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
|
||||||
"integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==",
|
"integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"freebsd"
|
"freebsd"
|
||||||
@@ -412,13 +419,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/freebsd-x64": {
|
"node_modules/@esbuild/freebsd-x64": {
|
||||||
"version": "0.20.2",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
|
||||||
"integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==",
|
"integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"freebsd"
|
"freebsd"
|
||||||
@@ -428,13 +436,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-arm": {
|
"node_modules/@esbuild/linux-arm": {
|
||||||
"version": "0.20.2",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
|
||||||
"integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==",
|
"integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
@@ -444,13 +453,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-arm64": {
|
"node_modules/@esbuild/linux-arm64": {
|
||||||
"version": "0.20.2",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
|
||||||
"integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==",
|
"integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
@@ -460,13 +470,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-ia32": {
|
"node_modules/@esbuild/linux-ia32": {
|
||||||
"version": "0.20.2",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
|
||||||
"integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==",
|
"integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
@@ -476,13 +487,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-loong64": {
|
"node_modules/@esbuild/linux-loong64": {
|
||||||
"version": "0.20.2",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
|
||||||
"integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==",
|
"integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"loong64"
|
"loong64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
@@ -492,13 +504,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-mips64el": {
|
"node_modules/@esbuild/linux-mips64el": {
|
||||||
"version": "0.20.2",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
|
||||||
"integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==",
|
"integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"mips64el"
|
"mips64el"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
@@ -508,13 +521,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-ppc64": {
|
"node_modules/@esbuild/linux-ppc64": {
|
||||||
"version": "0.20.2",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
|
||||||
"integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==",
|
"integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
@@ -524,13 +538,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-riscv64": {
|
"node_modules/@esbuild/linux-riscv64": {
|
||||||
"version": "0.20.2",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
|
||||||
"integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==",
|
"integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"riscv64"
|
"riscv64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
@@ -540,13 +555,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-s390x": {
|
"node_modules/@esbuild/linux-s390x": {
|
||||||
"version": "0.20.2",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
|
||||||
"integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==",
|
"integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"s390x"
|
"s390x"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
@@ -556,13 +572,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-x64": {
|
"node_modules/@esbuild/linux-x64": {
|
||||||
"version": "0.20.2",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
|
||||||
"integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==",
|
"integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
@@ -572,13 +589,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/netbsd-x64": {
|
"node_modules/@esbuild/netbsd-x64": {
|
||||||
"version": "0.20.2",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
|
||||||
"integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==",
|
"integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"netbsd"
|
"netbsd"
|
||||||
@@ -588,13 +606,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/openbsd-x64": {
|
"node_modules/@esbuild/openbsd-x64": {
|
||||||
"version": "0.20.2",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
|
||||||
"integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==",
|
"integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"openbsd"
|
"openbsd"
|
||||||
@@ -604,13 +623,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/sunos-x64": {
|
"node_modules/@esbuild/sunos-x64": {
|
||||||
"version": "0.20.2",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
|
||||||
"integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==",
|
"integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"sunos"
|
"sunos"
|
||||||
@@ -620,13 +640,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/win32-arm64": {
|
"node_modules/@esbuild/win32-arm64": {
|
||||||
"version": "0.20.2",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
|
||||||
"integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==",
|
"integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
@@ -636,13 +657,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/win32-ia32": {
|
"node_modules/@esbuild/win32-ia32": {
|
||||||
"version": "0.20.2",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
|
||||||
"integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==",
|
"integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
@@ -652,13 +674,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/win32-x64": {
|
"node_modules/@esbuild/win32-x64": {
|
||||||
"version": "0.20.2",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
|
||||||
"integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==",
|
"integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
@@ -1138,9 +1161,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "20.12.13",
|
"version": "20.14.9",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.13.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.9.tgz",
|
||||||
"integrity": "sha512-gBGeanV41c1L171rR7wjbMiEpEI/l5XFQdLLfhr/REwpgDy/4U8y89+i8kRiLzDyZdOkXh+cRaTetUnCYutoXA==",
|
"integrity": "sha512-06OCtnTXtWOZBJlRApleWndH4JsRVs1pDCc8dLSQp+7PpUpX3ePdHyeNSFTeSe7FtKyQkrlPvHwJOW3SLd8Oyg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -1154,17 +1177,17 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "7.11.0",
|
"version": "7.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.14.1.tgz",
|
||||||
"integrity": "sha512-P+qEahbgeHW4JQ/87FuItjBj8O3MYv5gELDzr8QaQ7fsll1gSMTYb6j87MYyxwf3DtD7uGFB9ShwgmCJB5KmaQ==",
|
"integrity": "sha512-aAJd6bIf2vvQRjUG3ZkNXkmBpN+J7Wd0mfQiiVCJMu9Z5GcZZdcc0j8XwN/BM97Fl7e3SkTXODSk4VehUv7CGw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/regexpp": "^4.10.0",
|
"@eslint-community/regexpp": "^4.10.0",
|
||||||
"@typescript-eslint/scope-manager": "7.11.0",
|
"@typescript-eslint/scope-manager": "7.14.1",
|
||||||
"@typescript-eslint/type-utils": "7.11.0",
|
"@typescript-eslint/type-utils": "7.14.1",
|
||||||
"@typescript-eslint/utils": "7.11.0",
|
"@typescript-eslint/utils": "7.14.1",
|
||||||
"@typescript-eslint/visitor-keys": "7.11.0",
|
"@typescript-eslint/visitor-keys": "7.14.1",
|
||||||
"graphemer": "^1.4.0",
|
"graphemer": "^1.4.0",
|
||||||
"ignore": "^5.3.1",
|
"ignore": "^5.3.1",
|
||||||
"natural-compare": "^1.4.0",
|
"natural-compare": "^1.4.0",
|
||||||
@@ -1188,16 +1211,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/parser": {
|
"node_modules/@typescript-eslint/parser": {
|
||||||
"version": "7.11.0",
|
"version": "7.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.14.1.tgz",
|
||||||
"integrity": "sha512-yimw99teuaXVWsBcPO1Ais02kwJ1jmNA1KxE7ng0aT7ndr1pT1wqj0OJnsYVGKKlc4QJai86l/025L6z8CljOg==",
|
"integrity": "sha512-8lKUOebNLcR0D7RvlcloOacTOWzOqemWEWkKSVpMZVF/XVcwjPR+3MD08QzbW9TCGJ+DwIc6zUSGZ9vd8cO1IA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "7.11.0",
|
"@typescript-eslint/scope-manager": "7.14.1",
|
||||||
"@typescript-eslint/types": "7.11.0",
|
"@typescript-eslint/types": "7.14.1",
|
||||||
"@typescript-eslint/typescript-estree": "7.11.0",
|
"@typescript-eslint/typescript-estree": "7.14.1",
|
||||||
"@typescript-eslint/visitor-keys": "7.11.0",
|
"@typescript-eslint/visitor-keys": "7.14.1",
|
||||||
"debug": "^4.3.4"
|
"debug": "^4.3.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1217,14 +1240,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/scope-manager": {
|
"node_modules/@typescript-eslint/scope-manager": {
|
||||||
"version": "7.11.0",
|
"version": "7.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.14.1.tgz",
|
||||||
"integrity": "sha512-27tGdVEiutD4POirLZX4YzT180vevUURJl4wJGmm6TrQoiYwuxTIY98PBp6L2oN+JQxzE0URvYlzJaBHIekXAw==",
|
"integrity": "sha512-gPrFSsoYcsffYXTOZ+hT7fyJr95rdVe4kGVX1ps/dJ+DfmlnjFN/GcMxXcVkeHDKqsq6uAcVaQaIi3cFffmAbA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "7.11.0",
|
"@typescript-eslint/types": "7.14.1",
|
||||||
"@typescript-eslint/visitor-keys": "7.11.0"
|
"@typescript-eslint/visitor-keys": "7.14.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || >=20.0.0"
|
"node": "^18.18.0 || >=20.0.0"
|
||||||
@@ -1235,14 +1258,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/type-utils": {
|
"node_modules/@typescript-eslint/type-utils": {
|
||||||
"version": "7.11.0",
|
"version": "7.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.14.1.tgz",
|
||||||
"integrity": "sha512-WmppUEgYy+y1NTseNMJ6mCFxt03/7jTOy08bcg7bxJJdsM4nuhnchyBbE8vryveaJUf62noH7LodPSo5Z0WUCg==",
|
"integrity": "sha512-/MzmgNd3nnbDbOi3LfasXWWe292+iuo+umJ0bCCMCPc1jLO/z2BQmWUUUXvXLbrQey/JgzdF/OV+I5bzEGwJkQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/typescript-estree": "7.11.0",
|
"@typescript-eslint/typescript-estree": "7.14.1",
|
||||||
"@typescript-eslint/utils": "7.11.0",
|
"@typescript-eslint/utils": "7.14.1",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"ts-api-utils": "^1.3.0"
|
"ts-api-utils": "^1.3.0"
|
||||||
},
|
},
|
||||||
@@ -1263,9 +1286,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/types": {
|
"node_modules/@typescript-eslint/types": {
|
||||||
"version": "7.11.0",
|
"version": "7.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.14.1.tgz",
|
||||||
"integrity": "sha512-MPEsDRZTyCiXkD4vd3zywDCifi7tatc4K37KqTprCvaXptP7Xlpdw0NR2hRJTetG5TxbWDB79Ys4kLmHliEo/w==",
|
"integrity": "sha512-mL7zNEOQybo5R3AavY+Am7KLv8BorIv7HCYS5rKoNZKQD9tsfGUpO4KdAn3sSUvTiS4PQkr2+K0KJbxj8H9NDg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1277,14 +1300,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree": {
|
"node_modules/@typescript-eslint/typescript-estree": {
|
||||||
"version": "7.11.0",
|
"version": "7.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.14.1.tgz",
|
||||||
"integrity": "sha512-cxkhZ2C/iyi3/6U9EPc5y+a6csqHItndvN/CzbNXTNrsC3/ASoYQZEt9uMaEp+xFNjasqQyszp5TumAVKKvJeQ==",
|
"integrity": "sha512-k5d0VuxViE2ulIO6FbxxSZaxqDVUyMbXcidC8rHvii0I56XZPv8cq+EhMns+d/EVIL41sMXqRbK3D10Oza1bbA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "7.11.0",
|
"@typescript-eslint/types": "7.14.1",
|
||||||
"@typescript-eslint/visitor-keys": "7.11.0",
|
"@typescript-eslint/visitor-keys": "7.14.1",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"globby": "^11.1.0",
|
"globby": "^11.1.0",
|
||||||
"is-glob": "^4.0.3",
|
"is-glob": "^4.0.3",
|
||||||
@@ -1306,16 +1329,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/utils": {
|
"node_modules/@typescript-eslint/utils": {
|
||||||
"version": "7.11.0",
|
"version": "7.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.14.1.tgz",
|
||||||
"integrity": "sha512-xlAWwPleNRHwF37AhrZurOxA1wyXowW4PqVXZVUNCLjB48CqdPJoJWkrpH2nij9Q3Lb7rtWindtoXwxjxlKKCA==",
|
"integrity": "sha512-CMmVVELns3nak3cpJhZosDkm63n+DwBlDX8g0k4QUa9BMnF+lH2lr3d130M1Zt1xxmB3LLk3NV7KQCq86ZBBhQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.4.0",
|
"@eslint-community/eslint-utils": "^4.4.0",
|
||||||
"@typescript-eslint/scope-manager": "7.11.0",
|
"@typescript-eslint/scope-manager": "7.14.1",
|
||||||
"@typescript-eslint/types": "7.11.0",
|
"@typescript-eslint/types": "7.14.1",
|
||||||
"@typescript-eslint/typescript-estree": "7.11.0"
|
"@typescript-eslint/typescript-estree": "7.14.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || >=20.0.0"
|
"node": "^18.18.0 || >=20.0.0"
|
||||||
@@ -1329,13 +1352,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/visitor-keys": {
|
"node_modules/@typescript-eslint/visitor-keys": {
|
||||||
"version": "7.11.0",
|
"version": "7.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.14.1.tgz",
|
||||||
"integrity": "sha512-7syYk4MzjxTEk0g/w3iqtgxnFQspDJfn6QKD36xMuuhTzjcxY7F8EmBLnALjVyaOF1/bVocu3bS/2/F7rXrveQ==",
|
"integrity": "sha512-Crb+F75U1JAEtBeQGxSKwI60hZmmzaqA3z9sYsVm8X7W5cwLEm5bRe0/uXS6+MR/y8CVpKSR/ontIAIEPFcEkA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "7.11.0",
|
"@typescript-eslint/types": "7.14.1",
|
||||||
"eslint-visitor-keys": "^3.4.3"
|
"eslint-visitor-keys": "^3.4.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1476,10 +1499,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.11.3",
|
"version": "8.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz",
|
||||||
"integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
|
"integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
},
|
},
|
||||||
@@ -1934,11 +1958,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/esbuild": {
|
"node_modules/esbuild": {
|
||||||
"version": "0.20.2",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
|
||||||
"integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==",
|
"integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"esbuild": "bin/esbuild"
|
"esbuild": "bin/esbuild"
|
||||||
},
|
},
|
||||||
@@ -1946,29 +1971,29 @@
|
|||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@esbuild/aix-ppc64": "0.20.2",
|
"@esbuild/aix-ppc64": "0.21.5",
|
||||||
"@esbuild/android-arm": "0.20.2",
|
"@esbuild/android-arm": "0.21.5",
|
||||||
"@esbuild/android-arm64": "0.20.2",
|
"@esbuild/android-arm64": "0.21.5",
|
||||||
"@esbuild/android-x64": "0.20.2",
|
"@esbuild/android-x64": "0.21.5",
|
||||||
"@esbuild/darwin-arm64": "0.20.2",
|
"@esbuild/darwin-arm64": "0.21.5",
|
||||||
"@esbuild/darwin-x64": "0.20.2",
|
"@esbuild/darwin-x64": "0.21.5",
|
||||||
"@esbuild/freebsd-arm64": "0.20.2",
|
"@esbuild/freebsd-arm64": "0.21.5",
|
||||||
"@esbuild/freebsd-x64": "0.20.2",
|
"@esbuild/freebsd-x64": "0.21.5",
|
||||||
"@esbuild/linux-arm": "0.20.2",
|
"@esbuild/linux-arm": "0.21.5",
|
||||||
"@esbuild/linux-arm64": "0.20.2",
|
"@esbuild/linux-arm64": "0.21.5",
|
||||||
"@esbuild/linux-ia32": "0.20.2",
|
"@esbuild/linux-ia32": "0.21.5",
|
||||||
"@esbuild/linux-loong64": "0.20.2",
|
"@esbuild/linux-loong64": "0.21.5",
|
||||||
"@esbuild/linux-mips64el": "0.20.2",
|
"@esbuild/linux-mips64el": "0.21.5",
|
||||||
"@esbuild/linux-ppc64": "0.20.2",
|
"@esbuild/linux-ppc64": "0.21.5",
|
||||||
"@esbuild/linux-riscv64": "0.20.2",
|
"@esbuild/linux-riscv64": "0.21.5",
|
||||||
"@esbuild/linux-s390x": "0.20.2",
|
"@esbuild/linux-s390x": "0.21.5",
|
||||||
"@esbuild/linux-x64": "0.20.2",
|
"@esbuild/linux-x64": "0.21.5",
|
||||||
"@esbuild/netbsd-x64": "0.20.2",
|
"@esbuild/netbsd-x64": "0.21.5",
|
||||||
"@esbuild/openbsd-x64": "0.20.2",
|
"@esbuild/openbsd-x64": "0.21.5",
|
||||||
"@esbuild/sunos-x64": "0.20.2",
|
"@esbuild/sunos-x64": "0.21.5",
|
||||||
"@esbuild/win32-arm64": "0.20.2",
|
"@esbuild/win32-arm64": "0.21.5",
|
||||||
"@esbuild/win32-ia32": "0.20.2",
|
"@esbuild/win32-ia32": "0.21.5",
|
||||||
"@esbuild/win32-x64": "0.20.2"
|
"@esbuild/win32-x64": "0.21.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/escalade": {
|
"node_modules/escalade": {
|
||||||
@@ -2090,10 +2115,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint-plugin-unicorn": {
|
"node_modules/eslint-plugin-unicorn": {
|
||||||
"version": "53.0.0",
|
"version": "54.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-53.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-54.0.0.tgz",
|
||||||
"integrity": "sha512-kuTcNo9IwwUCfyHGwQFOK/HjJAYzbODHN3wP0PgqbW+jbXqpNWxNVpVhj2tO9SixBwuAdmal8rVcWKBxwFnGuw==",
|
"integrity": "sha512-XxYLRiYtAWiAjPv6z4JREby1TAE2byBC7wlh0V4vWDCpccOSU1KovWV//jqPXF6bq3WKxqX9rdjoRQ1EhdmNdQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-validator-identifier": "^7.24.5",
|
"@babel/helper-validator-identifier": "^7.24.5",
|
||||||
"@eslint-community/eslint-utils": "^4.4.0",
|
"@eslint-community/eslint-utils": "^4.4.0",
|
||||||
@@ -2123,10 +2149,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint-plugin-unicorn/node_modules/@eslint/eslintrc": {
|
"node_modules/eslint-plugin-unicorn/node_modules/@eslint/eslintrc": {
|
||||||
"version": "3.0.2",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz",
|
||||||
"integrity": "sha512-wV19ZEGEMAC1eHgrS7UQPqsdEiCIbTKTasEfcXAigzoXICcqZSjBZEHlZwNVvKg6UBCjSlos84XiLqsRJnIcIg==",
|
"integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ajv": "^6.12.4",
|
"ajv": "^6.12.4",
|
||||||
"debug": "^4.3.2",
|
"debug": "^4.3.2",
|
||||||
@@ -2150,6 +2177,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"balanced-match": "^1.0.0",
|
"balanced-match": "^1.0.0",
|
||||||
"concat-map": "0.0.1"
|
"concat-map": "0.0.1"
|
||||||
@@ -2160,6 +2188,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz",
|
||||||
"integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==",
|
"integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
},
|
},
|
||||||
@@ -2168,12 +2197,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint-plugin-unicorn/node_modules/espree": {
|
"node_modules/eslint-plugin-unicorn/node_modules/espree": {
|
||||||
"version": "10.0.1",
|
"version": "10.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/espree/-/espree-10.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz",
|
||||||
"integrity": "sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==",
|
"integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"acorn": "^8.11.3",
|
"acorn": "^8.12.0",
|
||||||
"acorn-jsx": "^5.3.2",
|
"acorn-jsx": "^5.3.2",
|
||||||
"eslint-visitor-keys": "^4.0.0"
|
"eslint-visitor-keys": "^4.0.0"
|
||||||
},
|
},
|
||||||
@@ -2189,6 +2219,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
|
||||||
"integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
|
"integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
},
|
},
|
||||||
@@ -2201,6 +2232,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^1.1.7"
|
||||||
},
|
},
|
||||||
@@ -3048,9 +3080,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/minimatch": {
|
"node_modules/minimatch": {
|
||||||
"version": "9.0.4",
|
"version": "9.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
|
||||||
"integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
|
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -3411,10 +3443,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prettier": {
|
"node_modules/prettier": {
|
||||||
"version": "3.2.5",
|
"version": "3.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz",
|
||||||
"integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==",
|
"integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"prettier": "bin/prettier.cjs"
|
"prettier": "bin/prettier.cjs"
|
||||||
},
|
},
|
||||||
@@ -4207,10 +4240,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript": {
|
"node_modules/typescript": {
|
||||||
"version": "5.4.5",
|
"version": "5.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.2.tgz",
|
||||||
"integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
|
"integrity": "sha512-NcRtPEOsPFFWjobJEtfihkLCZCXZt/os3zf8nTxjVH3RvTSxjrCamJpbExGvYOF+tFHc3pA65qpdwPbzjohhew==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
@@ -4281,13 +4315,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "5.2.12",
|
"version": "5.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.2.12.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-5.3.2.tgz",
|
||||||
"integrity": "sha512-/gC8GxzxMK5ntBwb48pR32GGhENnjtY30G4A0jemunsBkiEZFw60s8InGpN8gkhHEkjnRK1aSAxeQgwvFhUHAA==",
|
"integrity": "sha512-6lA7OBHBlXUxiJxbO5aAY2fsHHzDr1q7DvXYnyZycRs2Dz+dXBWuhpWHvmljTRTpQC2uvGmUFFkSHF2vGo90MA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.20.1",
|
"esbuild": "^0.21.3",
|
||||||
"postcss": "^8.4.38",
|
"postcss": "^8.4.38",
|
||||||
"rollup": "^4.13.0"
|
"rollup": "^4.13.0"
|
||||||
},
|
},
|
||||||
@@ -4480,10 +4514,11 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/yaml": {
|
"node_modules/yaml": {
|
||||||
"version": "2.4.2",
|
"version": "2.4.5",
|
||||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.5.tgz",
|
||||||
"integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==",
|
"integrity": "sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "ISC",
|
||||||
"bin": {
|
"bin": {
|
||||||
"yaml": "bin.mjs"
|
"yaml": "bin.mjs"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@immich/cli",
|
"name": "@immich/cli",
|
||||||
"version": "2.2.4",
|
"version": "2.2.7",
|
||||||
"description": "Command Line Interface (CLI) for Immich",
|
"description": "Command Line Interface (CLI) for Immich",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": "./dist/index.js",
|
"exports": "./dist/index.js",
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
"@types/cli-progress": "^3.11.0",
|
"@types/cli-progress": "^3.11.0",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/mock-fs": "^4.13.1",
|
"@types/mock-fs": "^4.13.1",
|
||||||
"@types/node": "^20.3.1",
|
"@types/node": "^20.14.9",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
||||||
"@typescript-eslint/parser": "^7.0.0",
|
"@typescript-eslint/parser": "^7.0.0",
|
||||||
"@vitest/coverage-v8": "^1.2.2",
|
"@vitest/coverage-v8": "^1.2.2",
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
"eslint": "^8.56.0",
|
"eslint": "^8.56.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-prettier": "^5.1.3",
|
"eslint-plugin-prettier": "^5.1.3",
|
||||||
"eslint-plugin-unicorn": "^53.0.0",
|
"eslint-plugin-unicorn": "^54.0.0",
|
||||||
"mock-fs": "^5.2.0",
|
"mock-fs": "^5.2.0",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
"prettier-plugin-organize-imports": "^3.2.4",
|
"prettier-plugin-organize-imports": "^3.2.4",
|
||||||
@@ -62,6 +62,6 @@
|
|||||||
"lodash-es": "^4.17.21"
|
"lodash-es": "^4.17.21"
|
||||||
},
|
},
|
||||||
"volta": {
|
"volta": {
|
||||||
"node": "20.14.0"
|
"node": "20.15.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
19
cli/src/commands/asset.spec.ts
Normal file
19
cli/src/commands/asset.spec.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { platform } from 'node:os';
|
||||||
|
import { UploadOptionsDto, getAlbumName } from 'src/commands/asset';
|
||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
|
describe('Unit function tests', () => {
|
||||||
|
it('should return a non-undefined value', () => {
|
||||||
|
if (platform() === 'win32') {
|
||||||
|
// This is meaningless for Unix systems.
|
||||||
|
expect(getAlbumName(String.raw`D:\test\Filename.txt`, {} as UploadOptionsDto)).toBe('test');
|
||||||
|
}
|
||||||
|
expect(getAlbumName('D:/parentfolder/test/Filename.txt', {} as UploadOptionsDto)).toBe('test');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('has higher priority to return `albumName` in `options`', () => {
|
||||||
|
expect(getAlbumName('/parentfolder/test/Filename.txt', { albumName: 'example' } as UploadOptionsDto)).toBe(
|
||||||
|
'example',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -15,7 +15,6 @@ import { Presets, SingleBar } from 'cli-progress';
|
|||||||
import { chunk } from 'lodash-es';
|
import { chunk } from 'lodash-es';
|
||||||
import { Stats, createReadStream } from 'node:fs';
|
import { Stats, createReadStream } from 'node:fs';
|
||||||
import { stat, unlink } from 'node:fs/promises';
|
import { stat, unlink } from 'node:fs/promises';
|
||||||
import os from 'node:os';
|
|
||||||
import path, { basename } from 'node:path';
|
import path, { basename } from 'node:path';
|
||||||
import { BaseOptions, authenticate, crawl, sha1 } from 'src/utils';
|
import { BaseOptions, authenticate, crawl, sha1 } from 'src/utils';
|
||||||
|
|
||||||
@@ -25,7 +24,7 @@ const s = (count: number) => (count === 1 ? '' : 's');
|
|||||||
type AssetBulkUploadCheckResults = Array<AssetBulkUploadCheckResult & { id: string }>;
|
type AssetBulkUploadCheckResults = Array<AssetBulkUploadCheckResult & { id: string }>;
|
||||||
type Asset = { id: string; filepath: string };
|
type Asset = { id: string; filepath: string };
|
||||||
|
|
||||||
interface UploadOptionsDto {
|
export interface UploadOptionsDto {
|
||||||
recursive?: boolean;
|
recursive?: boolean;
|
||||||
ignore?: string;
|
ignore?: string;
|
||||||
dryRun?: boolean;
|
dryRun?: boolean;
|
||||||
@@ -346,7 +345,9 @@ const updateAlbums = async (assets: Asset[], options: UploadOptionsDto) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getAlbumName = (filepath: string, options: UploadOptionsDto) => {
|
// `filepath` valid format:
|
||||||
const folderName = os.platform() === 'win32' ? filepath.split('\\').at(-2) : filepath.split('/').at(-2);
|
// - Windows: `D:\\test\\Filename.txt` or `D:/test/Filename.txt`
|
||||||
return options.albumName ?? folderName;
|
// - Unix: `/test/Filename.txt`
|
||||||
|
export const getAlbumName = (filepath: string, options: UploadOptionsDto) => {
|
||||||
|
return options.albumName ?? path.basename(path.dirname(filepath));
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import mockfs from 'mock-fs';
|
import mockfs from 'mock-fs';
|
||||||
|
import { readFileSync } from 'node:fs';
|
||||||
import { CrawlOptions, crawl } from 'src/utils';
|
import { CrawlOptions, crawl } from 'src/utils';
|
||||||
|
|
||||||
interface Test {
|
interface Test {
|
||||||
@@ -9,6 +10,10 @@ interface Test {
|
|||||||
|
|
||||||
const cwd = process.cwd();
|
const cwd = process.cwd();
|
||||||
|
|
||||||
|
const readContent = (path: string) => {
|
||||||
|
return readFileSync(path).toString();
|
||||||
|
};
|
||||||
|
|
||||||
const extensions = [
|
const extensions = [
|
||||||
'.jpg',
|
'.jpg',
|
||||||
'.jpeg',
|
'.jpeg',
|
||||||
@@ -256,7 +261,8 @@ const tests: Test[] = [
|
|||||||
{
|
{
|
||||||
test: 'should support ignoring absolute paths',
|
test: 'should support ignoring absolute paths',
|
||||||
options: {
|
options: {
|
||||||
pathsToCrawl: ['/'],
|
// Currently, fast-glob has some caveat when dealing with `/`.
|
||||||
|
pathsToCrawl: ['/*s'],
|
||||||
recursive: true,
|
recursive: true,
|
||||||
exclusionPattern: '/images/**',
|
exclusionPattern: '/images/**',
|
||||||
},
|
},
|
||||||
@@ -276,14 +282,16 @@ describe('crawl', () => {
|
|||||||
describe('crawl', () => {
|
describe('crawl', () => {
|
||||||
for (const { test, options, files } of tests) {
|
for (const { test, options, files } of tests) {
|
||||||
it(test, async () => {
|
it(test, async () => {
|
||||||
mockfs(Object.fromEntries(Object.keys(files).map((file) => [file, ''])));
|
// The file contents is the same as the path.
|
||||||
|
mockfs(Object.fromEntries(Object.keys(files).map((file) => [file, file])));
|
||||||
|
|
||||||
const actual = await crawl({ ...options, extensions });
|
const actual = await crawl({ ...options, extensions });
|
||||||
const expected = Object.entries(files)
|
const expected = Object.entries(files)
|
||||||
.filter((entry) => entry[1])
|
.filter((entry) => entry[1])
|
||||||
.map(([file]) => file);
|
.map(([file]) => file);
|
||||||
|
|
||||||
expect(actual.sort()).toEqual(expected.sort());
|
// Compare file's content instead of path since a file can be represent in multiple ways.
|
||||||
|
expect(actual.map((path) => readContent(path)).sort()).toEqual(expected.sort());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { getMyUser, init, isHttpError } from '@immich/sdk';
|
import { getMyUser, init, isHttpError } from '@immich/sdk';
|
||||||
import { glob } from 'fast-glob';
|
import { convertPathToPattern, glob } from 'fast-glob';
|
||||||
import { createHash } from 'node:crypto';
|
import { createHash } from 'node:crypto';
|
||||||
import { createReadStream } from 'node:fs';
|
import { createReadStream } from 'node:fs';
|
||||||
import { readFile, stat, writeFile } from 'node:fs/promises';
|
import { readFile, stat, writeFile } from 'node:fs/promises';
|
||||||
|
import { platform } from 'node:os';
|
||||||
import { join, resolve } from 'node:path';
|
import { join, resolve } from 'node:path';
|
||||||
import yaml from 'yaml';
|
import yaml from 'yaml';
|
||||||
|
|
||||||
@@ -106,6 +107,11 @@ export interface CrawlOptions {
|
|||||||
exclusionPattern?: string;
|
exclusionPattern?: string;
|
||||||
extensions: string[];
|
extensions: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const convertPathToPatternOnWin = (path: string) => {
|
||||||
|
return platform() === 'win32' ? convertPathToPattern(path) : path;
|
||||||
|
};
|
||||||
|
|
||||||
export const crawl = async (options: CrawlOptions): Promise<string[]> => {
|
export const crawl = async (options: CrawlOptions): Promise<string[]> => {
|
||||||
const { extensions: extensionsWithPeriod, recursive, pathsToCrawl, exclusionPattern, includeHidden } = options;
|
const { extensions: extensionsWithPeriod, recursive, pathsToCrawl, exclusionPattern, includeHidden } = options;
|
||||||
const extensions = extensionsWithPeriod.map((extension) => extension.replace('.', ''));
|
const extensions = extensionsWithPeriod.map((extension) => extension.replace('.', ''));
|
||||||
@@ -124,11 +130,11 @@ export const crawl = async (options: CrawlOptions): Promise<string[]> => {
|
|||||||
if (stats.isFile() || stats.isSymbolicLink()) {
|
if (stats.isFile() || stats.isSymbolicLink()) {
|
||||||
crawledFiles.push(absolutePath);
|
crawledFiles.push(absolutePath);
|
||||||
} else {
|
} else {
|
||||||
patterns.push(absolutePath);
|
patterns.push(convertPathToPatternOnWin(absolutePath));
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
if (error.code === 'ENOENT') {
|
if (error.code === 'ENOENT') {
|
||||||
patterns.push(currentPath);
|
patterns.push(convertPathToPatternOnWin(currentPath));
|
||||||
} else {
|
} else {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { defineConfig } from 'vite';
|
|||||||
import tsconfigPaths from 'vite-tsconfig-paths';
|
import tsconfigPaths from 'vite-tsconfig-paths';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
resolve: { alias: { src: '/src' } },
|
||||||
build: {
|
build: {
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
input: 'src/index.ts',
|
input: 'src/index.ts',
|
||||||
|
|||||||
@@ -2,37 +2,37 @@
|
|||||||
# Manual edits may be lost in future updates.
|
# Manual edits may be lost in future updates.
|
||||||
|
|
||||||
provider "registry.opentofu.org/cloudflare/cloudflare" {
|
provider "registry.opentofu.org/cloudflare/cloudflare" {
|
||||||
version = "4.34.0"
|
version = "4.36.0"
|
||||||
constraints = "4.34.0"
|
constraints = "4.36.0"
|
||||||
hashes = [
|
hashes = [
|
||||||
"h1:+W0+Xe1AUh7yvHjDbgR9T7CY1UbBC3Y6U7Eo+ucLnJM=",
|
"h1:00/Y+l17VV4RquGSfwDnYsGYzyf2ZmdQwUgeIzXC7eg=",
|
||||||
"h1:2+1lKObDDdFZRluvROF3RKtXD66CFT3PfnHOvR6CmfA=",
|
"h1:489GpKItA/VRIUA5S4+F8MsnurGVciRvUFyIV81MJTU=",
|
||||||
"h1:7vluN2wmw8D9nI11YwTgoGv3hGDXlkt8xqQ4L/JABeQ=",
|
"h1:7cnczyKGj3+gvaJ0r5JIVWLXPbQfkHYejac76MJx+I8=",
|
||||||
"h1:B0Urm8ZKTJ8cXzSCtEpJ+o+LsD8MXaD6LU59qVbh50Q=",
|
"h1:8rmr1PjJc14Xmor2eEvo5/WBojylt1eYdx6VbSU3Ulo=",
|
||||||
"h1:FpGLCm5oF12FaRti3E4iQJlkVbdCC7toyGVuH8og7KY=",
|
"h1:HjgphNjtgny5tkcUAQoGgBdcuQ+0IyhL8yLsiBqWAP0=",
|
||||||
"h1:FunTmrCMDy+rom7YskY0WiL5/Y164zFrrD9xnBxU5NY=",
|
"h1:LH3umxdBnJcAyeVoBLVn+PC0F0CzN6v9UN6lb6CqQPE=",
|
||||||
"h1:GrxZhEb+5HzmHF/BvZBdGKBJy6Wyjme0+ABVDz/63to=",
|
"h1:Xx6WUD/zB8fM9SjkFx06Fgx2K7aGJIVvsJS2pwqALEM=",
|
||||||
"h1:J36dda2K42/oTfHuZ4jKkW5+nI6BTWFRUvo60P17NJg=",
|
"h1:YizL5YN9zQ8YkSR6V/G201YrCVdnkF9EUIK4lpROWiA=",
|
||||||
"h1:Kq0Wyn+j6zoQeghMYixbnfnyP9ZSIEJbOCzMbaCiAQQ=",
|
"h1:aPcXVGjYcCJdqvWSzc/dEjwj05LnbWZje8IanygVjcI=",
|
||||||
"h1:TKxunXCiS/z105sN/kBNFwU6tIKD67JKJ3ZKjwzoCuI=",
|
"h1:eKCvfashdCqfDcFGXE2gq+XxAURD5SzuaQ9Brs3zLos=",
|
||||||
"h1:TR0URKFQxsRO5/v7bKm5hkD/CTTjsG7aVGllL/Mf25c=",
|
"h1:gpKcBYkBcfn/uF1A8W7MD/OysMZW7EU4QVYvPEEnxGc=",
|
||||||
"h1:V+3Qs0Reb6r+8p4XjE5ZFDWYrOIN0x5SwORz4wvHOJ4=",
|
"h1:kCkcxZZnkKAnMz9scUQHb19d9/l9FPOHovAyrvtA618=",
|
||||||
"h1:mZB3Ui7V/lPQMQK53eBOjIHcrul74252dT06Kgn3J+s=",
|
"h1:t8mXXnICTeKqoD29uvyLFHVWMfMzTUrJuHje8lpI0zU=",
|
||||||
"h1:wJwZrIXxoki8omXLJ7XA7B1KaSrtcLMJp090fRtFRAc=",
|
"h1:zjzavjIdLDGRYsWd3v0HJz6ul12Cewj9RW/cqAQ4DxI=",
|
||||||
"zh:02aa46743c1585ada8faa7db23af68ea614053a506f88f05d1090ff5e0e68076",
|
"zh:02665712b3893307596b3caab99cf1f2502d5caca18e22d4b37bb535e628e102",
|
||||||
"zh:1e1a545e83e6457a0e15357b23139bc288fb4fbd5e9a5ddfedc95a6a0216b08c",
|
"zh:1514b0d3ef62934484ac471113ee68cddec0c21e56b4f710922741fe9b6e6fdf",
|
||||||
"zh:29eef2621e0b1501f620e615bf73b1b90d5417d745e38af63634bc03250faf87",
|
"zh:1fab4dfcecbcea13267b42e5ff05ba0692aa2dcb247b8e633fea0daf49feb156",
|
||||||
"zh:3c20989d7e1e141882e6091384bf85fdc83f70f3d29e3e047c493a07de992095",
|
"zh:24d8367295fe1f1b2be37802aecb96edf32f743364663ffe781d1bb92438395d",
|
||||||
"zh:3d39619379ba29c7ffb15196f0ea72a04c84cfcdf4b39ac42ac4cf4c19f3eae2",
|
"zh:34e84e7940c99dcf65663cfd25afac22bf5c8a5ff2cd21900c67180d3a072be9",
|
||||||
"zh:805f4a2774e9279c590b8214aabe6df9dcc22bb995df2530513f2f78c647ce75",
|
"zh:3d71d63204a329acf1d1de8638f2c725243cb94cf444d2d7acde54b3d1ac1696",
|
||||||
|
"zh:57831ba88e779a762bcfa224ba9eac8bc22ef9cd70cd541d848b351e0ba6a75c",
|
||||||
|
"zh:6407560f2e548afcb4852c91efc664627a9ee565c31a9c81fc9ea1806fca0567",
|
||||||
|
"zh:738ddbc664d75f4859aa09444a27809bc398795a8ea8f5be8531040690287712",
|
||||||
|
"zh:841ca2b2d78b6f8d33ec3435bc090c5e04a3a7d85c80df11227a7ea00d36f6b1",
|
||||||
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
|
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
|
||||||
"zh:8af716f8655a57aa986861a8a7fa1d724594a284bd77c870eaea4db5f8b9732d",
|
"zh:8b3d3d63354032ab9b2403c50728e9aa4e83c7367eaad2d18794221addeafc0f",
|
||||||
"zh:a3d13c93b4e6ee6004782debaa9a17f990f2fe8ec8ba545c232818bb6064aba9",
|
"zh:9e293443fe3127e488f540229983c1b9688268185f87567bb3d18e794697acd2",
|
||||||
"zh:bfa136acf82d3719473c0064446cc16d1b0303d98b06f55f503b7abeebceadb1",
|
"zh:b3a22439156e46461213db183e2e89569cd2e8d7cbcfc4b9f90469090e105807",
|
||||||
"zh:ca6cf9254ae5436f2efbc01a0e3f7e4aa3c08b45182037b3eb3eb9539b2f7aec",
|
"zh:f430feb5d51891e84028459e57039045dea4f1f5fcf671161d8ac2d8f28763f3",
|
||||||
"zh:cba32d5de02674004e0a5955bd5222016d9991ca0553d4bd3bea517cd9def6ab",
|
|
||||||
"zh:d22c8cd527c6d0e84567f57be5911792e2fcd5969e3bba3747489f18bb16705b",
|
|
||||||
"zh:e4eeede9b3e72cdadd6cc252d4cbcf41baee6ecfd12bacd927e2dcbe733ab210",
|
|
||||||
"zh:facdaa787a69f86203cd3cc6922baea0b4a18bd9c36b0a8162e2e88ef6c90655",
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ terraform {
|
|||||||
required_providers {
|
required_providers {
|
||||||
cloudflare = {
|
cloudflare = {
|
||||||
source = "cloudflare/cloudflare"
|
source = "cloudflare/cloudflare"
|
||||||
version = "4.34.0"
|
version = "4.36.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,37 +2,37 @@
|
|||||||
# Manual edits may be lost in future updates.
|
# Manual edits may be lost in future updates.
|
||||||
|
|
||||||
provider "registry.opentofu.org/cloudflare/cloudflare" {
|
provider "registry.opentofu.org/cloudflare/cloudflare" {
|
||||||
version = "4.34.0"
|
version = "4.36.0"
|
||||||
constraints = "4.34.0"
|
constraints = "4.36.0"
|
||||||
hashes = [
|
hashes = [
|
||||||
"h1:+W0+Xe1AUh7yvHjDbgR9T7CY1UbBC3Y6U7Eo+ucLnJM=",
|
"h1:00/Y+l17VV4RquGSfwDnYsGYzyf2ZmdQwUgeIzXC7eg=",
|
||||||
"h1:2+1lKObDDdFZRluvROF3RKtXD66CFT3PfnHOvR6CmfA=",
|
"h1:489GpKItA/VRIUA5S4+F8MsnurGVciRvUFyIV81MJTU=",
|
||||||
"h1:7vluN2wmw8D9nI11YwTgoGv3hGDXlkt8xqQ4L/JABeQ=",
|
"h1:7cnczyKGj3+gvaJ0r5JIVWLXPbQfkHYejac76MJx+I8=",
|
||||||
"h1:B0Urm8ZKTJ8cXzSCtEpJ+o+LsD8MXaD6LU59qVbh50Q=",
|
"h1:8rmr1PjJc14Xmor2eEvo5/WBojylt1eYdx6VbSU3Ulo=",
|
||||||
"h1:FpGLCm5oF12FaRti3E4iQJlkVbdCC7toyGVuH8og7KY=",
|
"h1:HjgphNjtgny5tkcUAQoGgBdcuQ+0IyhL8yLsiBqWAP0=",
|
||||||
"h1:FunTmrCMDy+rom7YskY0WiL5/Y164zFrrD9xnBxU5NY=",
|
"h1:LH3umxdBnJcAyeVoBLVn+PC0F0CzN6v9UN6lb6CqQPE=",
|
||||||
"h1:GrxZhEb+5HzmHF/BvZBdGKBJy6Wyjme0+ABVDz/63to=",
|
"h1:Xx6WUD/zB8fM9SjkFx06Fgx2K7aGJIVvsJS2pwqALEM=",
|
||||||
"h1:J36dda2K42/oTfHuZ4jKkW5+nI6BTWFRUvo60P17NJg=",
|
"h1:YizL5YN9zQ8YkSR6V/G201YrCVdnkF9EUIK4lpROWiA=",
|
||||||
"h1:Kq0Wyn+j6zoQeghMYixbnfnyP9ZSIEJbOCzMbaCiAQQ=",
|
"h1:aPcXVGjYcCJdqvWSzc/dEjwj05LnbWZje8IanygVjcI=",
|
||||||
"h1:TKxunXCiS/z105sN/kBNFwU6tIKD67JKJ3ZKjwzoCuI=",
|
"h1:eKCvfashdCqfDcFGXE2gq+XxAURD5SzuaQ9Brs3zLos=",
|
||||||
"h1:TR0URKFQxsRO5/v7bKm5hkD/CTTjsG7aVGllL/Mf25c=",
|
"h1:gpKcBYkBcfn/uF1A8W7MD/OysMZW7EU4QVYvPEEnxGc=",
|
||||||
"h1:V+3Qs0Reb6r+8p4XjE5ZFDWYrOIN0x5SwORz4wvHOJ4=",
|
"h1:kCkcxZZnkKAnMz9scUQHb19d9/l9FPOHovAyrvtA618=",
|
||||||
"h1:mZB3Ui7V/lPQMQK53eBOjIHcrul74252dT06Kgn3J+s=",
|
"h1:t8mXXnICTeKqoD29uvyLFHVWMfMzTUrJuHje8lpI0zU=",
|
||||||
"h1:wJwZrIXxoki8omXLJ7XA7B1KaSrtcLMJp090fRtFRAc=",
|
"h1:zjzavjIdLDGRYsWd3v0HJz6ul12Cewj9RW/cqAQ4DxI=",
|
||||||
"zh:02aa46743c1585ada8faa7db23af68ea614053a506f88f05d1090ff5e0e68076",
|
"zh:02665712b3893307596b3caab99cf1f2502d5caca18e22d4b37bb535e628e102",
|
||||||
"zh:1e1a545e83e6457a0e15357b23139bc288fb4fbd5e9a5ddfedc95a6a0216b08c",
|
"zh:1514b0d3ef62934484ac471113ee68cddec0c21e56b4f710922741fe9b6e6fdf",
|
||||||
"zh:29eef2621e0b1501f620e615bf73b1b90d5417d745e38af63634bc03250faf87",
|
"zh:1fab4dfcecbcea13267b42e5ff05ba0692aa2dcb247b8e633fea0daf49feb156",
|
||||||
"zh:3c20989d7e1e141882e6091384bf85fdc83f70f3d29e3e047c493a07de992095",
|
"zh:24d8367295fe1f1b2be37802aecb96edf32f743364663ffe781d1bb92438395d",
|
||||||
"zh:3d39619379ba29c7ffb15196f0ea72a04c84cfcdf4b39ac42ac4cf4c19f3eae2",
|
"zh:34e84e7940c99dcf65663cfd25afac22bf5c8a5ff2cd21900c67180d3a072be9",
|
||||||
"zh:805f4a2774e9279c590b8214aabe6df9dcc22bb995df2530513f2f78c647ce75",
|
"zh:3d71d63204a329acf1d1de8638f2c725243cb94cf444d2d7acde54b3d1ac1696",
|
||||||
|
"zh:57831ba88e779a762bcfa224ba9eac8bc22ef9cd70cd541d848b351e0ba6a75c",
|
||||||
|
"zh:6407560f2e548afcb4852c91efc664627a9ee565c31a9c81fc9ea1806fca0567",
|
||||||
|
"zh:738ddbc664d75f4859aa09444a27809bc398795a8ea8f5be8531040690287712",
|
||||||
|
"zh:841ca2b2d78b6f8d33ec3435bc090c5e04a3a7d85c80df11227a7ea00d36f6b1",
|
||||||
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
|
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
|
||||||
"zh:8af716f8655a57aa986861a8a7fa1d724594a284bd77c870eaea4db5f8b9732d",
|
"zh:8b3d3d63354032ab9b2403c50728e9aa4e83c7367eaad2d18794221addeafc0f",
|
||||||
"zh:a3d13c93b4e6ee6004782debaa9a17f990f2fe8ec8ba545c232818bb6064aba9",
|
"zh:9e293443fe3127e488f540229983c1b9688268185f87567bb3d18e794697acd2",
|
||||||
"zh:bfa136acf82d3719473c0064446cc16d1b0303d98b06f55f503b7abeebceadb1",
|
"zh:b3a22439156e46461213db183e2e89569cd2e8d7cbcfc4b9f90469090e105807",
|
||||||
"zh:ca6cf9254ae5436f2efbc01a0e3f7e4aa3c08b45182037b3eb3eb9539b2f7aec",
|
"zh:f430feb5d51891e84028459e57039045dea4f1f5fcf671161d8ac2d8f28763f3",
|
||||||
"zh:cba32d5de02674004e0a5955bd5222016d9991ca0553d4bd3bea517cd9def6ab",
|
|
||||||
"zh:d22c8cd527c6d0e84567f57be5911792e2fcd5969e3bba3747489f18bb16705b",
|
|
||||||
"zh:e4eeede9b3e72cdadd6cc252d4cbcf41baee6ecfd12bacd927e2dcbe733ab210",
|
|
||||||
"zh:facdaa787a69f86203cd3cc6922baea0b4a18bd9c36b0a8162e2e88ef6c90655",
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ terraform {
|
|||||||
required_providers {
|
required_providers {
|
||||||
cloudflare = {
|
cloudflare = {
|
||||||
source = "cloudflare/cloudflare"
|
source = "cloudflare/cloudflare"
|
||||||
version = "4.34.0"
|
version = "4.36.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,16 @@ services:
|
|||||||
- /etc/localtime:/etc/localtime:ro
|
- /etc/localtime:/etc/localtime:ro
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
|
environment:
|
||||||
|
IMMICH_REPOSITORY: immich-app/immich
|
||||||
|
IMMICH_REPOSITORY_URL: https://github.com/immich-app/immich
|
||||||
|
IMMICH_SOURCE_REF: local
|
||||||
|
IMMICH_SOURCE_COMMIT: af2efbdbbddc27cd06142f22253ccbbbbeec1f55
|
||||||
|
IMMICH_SOURCE_URL: https://github.com/immich-app/immich/commit/af2efbdbbddc27cd06142f22253ccbbbbeec1f55
|
||||||
|
IMMICH_BUILD: '9654404849'
|
||||||
|
IMMICH_BUILD_URL: https://github.com/immich-app/immich/actions/runs/9654404849
|
||||||
|
IMMICH_BUILD_IMAGE: development
|
||||||
|
IMMICH_BUILD_IMAGE_URL: https://github.com/immich-app/immich/pkgs/container/immich-server
|
||||||
ulimits:
|
ulimits:
|
||||||
nofile:
|
nofile:
|
||||||
soft: 1048576
|
soft: 1048576
|
||||||
@@ -84,7 +94,7 @@ services:
|
|||||||
|
|
||||||
redis:
|
redis:
|
||||||
container_name: immich_redis
|
container_name: immich_redis
|
||||||
image: redis:6.2-alpine@sha256:d6c2911ac51b289db208767581a5d154544f2b2fe4914ea5056443f62dc6e900
|
image: redis:6.2-alpine@sha256:328fe6a5822256d065debb36617a8169dbfbd77b797c525288e465f56c1d392b
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: redis-cli ping || exit 1
|
test: redis-cli ping || exit 1
|
||||||
|
|
||||||
@@ -103,11 +113,26 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- 5432:5432
|
- 5432:5432
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: pg_isready --dbname='${DB_DATABASE_NAME}' || exit 1; Chksum="$$(psql --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' --tuples-only --no-align --command='SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1
|
test: pg_isready --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' || exit 1; Chksum="$$(psql --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' --tuples-only --no-align --command='SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1
|
||||||
interval: 5m
|
interval: 5m
|
||||||
start_interval: 30s
|
start_interval: 30s
|
||||||
start_period: 5m
|
start_period: 5m
|
||||||
command: ["postgres", "-c" ,"shared_preload_libraries=vectors.so", "-c", 'search_path="$$user", public, vectors', "-c", "logging_collector=on", "-c", "max_wal_size=2GB", "-c", "shared_buffers=512MB", "-c", "wal_compression=on"]
|
command:
|
||||||
|
[
|
||||||
|
'postgres',
|
||||||
|
'-c',
|
||||||
|
'shared_preload_libraries=vectors.so',
|
||||||
|
'-c',
|
||||||
|
'search_path="$$user", public, vectors',
|
||||||
|
'-c',
|
||||||
|
'logging_collector=on',
|
||||||
|
'-c',
|
||||||
|
'max_wal_size=2GB',
|
||||||
|
'-c',
|
||||||
|
'shared_buffers=512MB',
|
||||||
|
'-c',
|
||||||
|
'wal_compression=on',
|
||||||
|
]
|
||||||
|
|
||||||
# set IMMICH_METRICS=true in .env to enable metrics
|
# set IMMICH_METRICS=true in .env to enable metrics
|
||||||
# immich-prometheus:
|
# immich-prometheus:
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ services:
|
|||||||
|
|
||||||
redis:
|
redis:
|
||||||
container_name: immich_redis
|
container_name: immich_redis
|
||||||
image: redis:6.2-alpine@sha256:d6c2911ac51b289db208767581a5d154544f2b2fe4914ea5056443f62dc6e900
|
image: redis:6.2-alpine@sha256:328fe6a5822256d065debb36617a8169dbfbd77b797c525288e465f56c1d392b
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: redis-cli ping || exit 1
|
test: redis-cli ping || exit 1
|
||||||
restart: always
|
restart: always
|
||||||
@@ -61,7 +61,7 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- 5432:5432
|
- 5432:5432
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: pg_isready --dbname='${DB_DATABASE_NAME}' || exit 1; Chksum="$$(psql --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' --tuples-only --no-align --command='SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1
|
test: pg_isready --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' || exit 1; Chksum="$$(psql --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' --tuples-only --no-align --command='SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1
|
||||||
interval: 5m
|
interval: 5m
|
||||||
start_interval: 30s
|
start_interval: 30s
|
||||||
start_period: 5m
|
start_period: 5m
|
||||||
@@ -73,7 +73,7 @@ services:
|
|||||||
container_name: immich_prometheus
|
container_name: immich_prometheus
|
||||||
ports:
|
ports:
|
||||||
- 9090:9090
|
- 9090:9090
|
||||||
image: prom/prometheus@sha256:5c435642ca4d8427ca26f4901c11114023004709037880cd7860d5b7176aa731
|
image: prom/prometheus@sha256:075b1ba2c4ebb04bc3a6ab86c06ec8d8099f8fda1c96ef6d104d9bb1def1d8bc
|
||||||
volumes:
|
volumes:
|
||||||
- ./prometheus.yml:/etc/prometheus/prometheus.yml
|
- ./prometheus.yml:/etc/prometheus/prometheus.yml
|
||||||
- prometheus-data:/prometheus
|
- prometheus-data:/prometheus
|
||||||
@@ -85,7 +85,7 @@ services:
|
|||||||
command: ['./run.sh', '-disable-reporting']
|
command: ['./run.sh', '-disable-reporting']
|
||||||
ports:
|
ports:
|
||||||
- 3000:3000
|
- 3000:3000
|
||||||
image: grafana/grafana:11.0.0-ubuntu@sha256:dcd3ae78713958a862732c3608d32c03f0c279c35a2032d74b80b12c5cdc47b8
|
image: grafana/grafana:11.1.0-ubuntu@sha256:c7fc29ec783d5e7fc1bdfaad6f92345a345cffbc5d21c388ca228175006fc107
|
||||||
volumes:
|
volumes:
|
||||||
- grafana-data:/var/lib/grafana
|
- grafana-data:/var/lib/grafana
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ services:
|
|||||||
|
|
||||||
redis:
|
redis:
|
||||||
container_name: immich_redis
|
container_name: immich_redis
|
||||||
image: docker.io/redis:6.2-alpine@sha256:d6c2911ac51b289db208767581a5d154544f2b2fe4914ea5056443f62dc6e900
|
image: docker.io/redis:6.2-alpine@sha256:328fe6a5822256d065debb36617a8169dbfbd77b797c525288e465f56c1d392b
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: redis-cli ping || exit 1
|
test: redis-cli ping || exit 1
|
||||||
restart: always
|
restart: always
|
||||||
@@ -59,7 +59,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
|
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: pg_isready --dbname='${DB_DATABASE_NAME}' || exit 1; Chksum="$$(psql --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' --tuples-only --no-align --command='SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1
|
test: pg_isready --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' || exit 1; Chksum="$$(psql --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' --tuples-only --no-align --command='SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1
|
||||||
interval: 5m
|
interval: 5m
|
||||||
start_interval: 30s
|
start_interval: 30s
|
||||||
start_period: 5m
|
start_period: 5m
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
20.14
|
20.15
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ Thank you, and I am asking for your support for the project. I hope to be a full
|
|||||||
- Bitcoin: 3QVAb9dCHutquVejeNXitPqZX26Yg5kxb7
|
- Bitcoin: 3QVAb9dCHutquVejeNXitPqZX26Yg5kxb7
|
||||||
- Give a project a star - the contributors love gazing at the stars and seeing their creations shining in the sky.
|
- Give a project a star - the contributors love gazing at the stars and seeing their creations shining in the sky.
|
||||||
|
|
||||||
Join our friendly [Discord](https://discord.gg/D8JsnBEuKb) to talk and discuss Immich, tech, or anything
|
Join our friendly [Discord](https://discord.immich.app) to talk and discuss Immich, tech, or anything
|
||||||
|
|
||||||
Cheer!
|
Cheer!
|
||||||
|
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ Thank you, and I am asking for your support for the project. I hope to be a full
|
|||||||
- Bitcoin: 3QVAb9dCHutquVejeNXitPqZX26Yg5kxb7
|
- Bitcoin: 3QVAb9dCHutquVejeNXitPqZX26Yg5kxb7
|
||||||
- Give a project a star - the contributors love gazing at the stars and seeing their creations shining in the sky.
|
- Give a project a star - the contributors love gazing at the stars and seeing their creations shining in the sky.
|
||||||
|
|
||||||
Join our friendly [Discord](https://discord.gg/D8JsnBEuKb) to talk and discuss Immich, tech, or anything
|
Join our friendly [Discord](https://discord.immich.app) to talk and discuss Immich, tech, or anything
|
||||||
|
|
||||||
Cheer!
|
Cheer!
|
||||||
|
|
||||||
|
|||||||
77
docs/blog/2024/update-july-2024.mdx
Normal file
77
docs/blog/2024/update-july-2024.mdx
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
---
|
||||||
|
title: Immich Update - July 2024
|
||||||
|
authors: [alextran]
|
||||||
|
tags: [update, v1.106.0]
|
||||||
|
---
|
||||||
|
|
||||||
|
Hello everybody! Alex from Immich here and I am back with another development progress update for the project.
|
||||||
|
|
||||||
|
Summer has returned once again, and the night sky is filled with stars, thank you for **38_000 shining stars** you have sent to our [GitHub repo](https://github.com/immich-app/immich)! Since the last announcement several core contributors have started full time. Everything is going great with development, PRs get merged with _brrrrrrr_ rate, conversation exchange between team members is on a new high, we met and are working with the great engineers at FUTO. The spirit is high and we have a lot of things brewing that we think you will like.
|
||||||
|
|
||||||
|
Let's go over some of the updates we had since the last post.
|
||||||
|
|
||||||
|
### Container consolidation
|
||||||
|
|
||||||
|
Reduced the number of total containers from 5 to 4 by making the microservices thread get spawned directly in the server container. Woohoo, remember when Immich had 7 containers?
|
||||||
|
|
||||||
|
### Email notifications
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
We added email notifications to the app with SMTP settings that you can configure for the following events
|
||||||
|
|
||||||
|
- A new account is created for you.
|
||||||
|
- You are added to a shared album.
|
||||||
|
- New media is added to an album.
|
||||||
|
|
||||||
|
### Versioned docs
|
||||||
|
|
||||||
|
You can now jump back into the past or take a peek at the unreleased version of the documentation by selecting the version on the website.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Similarity deduplication
|
||||||
|
|
||||||
|
With more machine learning and CLIP magic, we now have similarity deduplication built into the application where it will search for closely similar images and let you decide what to do with them; i.e keep or trash.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Permanent URL for asset on the web
|
||||||
|
|
||||||
|
The detail view for an asset now has a permanent URL so you can easily share them with your loved ones.
|
||||||
|
|
||||||
|
### Web app translations
|
||||||
|
|
||||||
|
We now have a public Weblate project which the community can use to translate the webapp to their native languages. We are planning to port the mobile app translation to this platform as well. If you would like to contribute, you can take a look [here](https://hosted.weblate.org/projects/immich/immich/). We're already close to 50% translations -- we really appreciate everyone contributing to that!
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Read-only/Editor mode on shared album
|
||||||
|
|
||||||
|
As the owner of the album, you can choose if the shared user can edit the album or to only view the content of the album without any modification.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Better video thumbnails
|
||||||
|
|
||||||
|
Immich now tries to find a descriptive video thumbnail instead of simply using the first frame. No more black images for thumbnails!
|
||||||
|
|
||||||
|
### Public Roadmap
|
||||||
|
|
||||||
|
We now have a [public roadmap](https://immich.app/roadmap), giving you a high-level overview of things the team is working on. The first goal of this roadmap is to bring Immich to a stable release, which is expected sometime later this year. Some of the highlights include
|
||||||
|
|
||||||
|
- Auto stacking - Auto stacking of burst photos
|
||||||
|
- Basic editor - Basic photo editing capabilities
|
||||||
|
- Workflows - Automate tasks with workflows
|
||||||
|
- Fine grained access controls - Granular access controls for users and api keys
|
||||||
|
- Better background backups - Rework background backups to be more reliable
|
||||||
|
- Private/locked photos - Private assets with extra protections
|
||||||
|
|
||||||
|
Beyond the items in the roadmap, we have _many many_ more ideas for Immich. The team and I hope that you are enjoying the application, find it helpful in your life and we have nothing but the intention of building out great software for you all!
|
||||||
|
|
||||||
|
Have an amazing Summer or Winter for those in the southern hemisphere! :D
|
||||||
|
|
||||||
|
Until next time,
|
||||||
|
|
||||||
|
Cheers!
|
||||||
|
Alex
|
||||||
@@ -408,4 +408,11 @@ docker exec -it immich_postgres psql --dbname=immich --username=<DB_USERNAME> --
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
If corruption is detected, you should immediately make a backup before performing any other work in the database.
|
||||||
|
To do so, you may need to set the `zero_damaged_pages=on` flag for the database server to allow `pg_dumpall` to succeed.
|
||||||
|
After taking a backup, the recommended next step is to restore the database from a healthy backup before corruption was detected.
|
||||||
|
The damaged database dump can be used to manually recover any changes made since the last backup, if needed.
|
||||||
|
|
||||||
|
The causes of possible corruption are many, but can include unexpected poweroffs or unmounts, use of a network share for Postgres data, or a poor storage medium such an SD card or failing HDD/SSD.
|
||||||
|
|
||||||
[huggingface]: https://huggingface.co/immich-app
|
[huggingface]: https://huggingface.co/immich-app
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ services:
|
|||||||
backup:
|
backup:
|
||||||
container_name: immich_db_dumper
|
container_name: immich_db_dumper
|
||||||
image: prodrigestivill/postgres-backup-local:14
|
image: prodrigestivill/postgres-backup-local:14
|
||||||
|
restart: always
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
environment:
|
environment:
|
||||||
@@ -191,6 +192,6 @@ When you turn off the storage template engine, it will leave the assets in `UPLO
|
|||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
:::danger
|
:::danger
|
||||||
Do not touch the files inside these folders under any circumstances except taking a backup, changing or removing an asset can cause untracked and missing files.
|
Do not touch the files inside these folders under any circumstances except taking a backup. Changing or removing an asset can cause untracked and missing files.
|
||||||
You can think of it as App-Which-Must-Not-Be-Named, the only access to viewing, changing and deleting assets is only through the mobile or browser interface.
|
You can think of it as App-Which-Must-Not-Be-Named, the only access to viewing, changing and deleting assets is only through the mobile or browser interface.
|
||||||
:::
|
:::
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ Copy the entire `immich-server` block as a new service and make the following ch
|
|||||||
+ container_name: immich_microservices
|
+ container_name: immich_microservices
|
||||||
```
|
```
|
||||||
|
|
||||||
Once you have two copies of the immich-server service, make the following chnages to each one. This will allow one container to only serve the web UI and API, and the other one to handle all other tasks.
|
Once you have two copies of the immich-server service, make the following changes to each one. This will allow one container to only serve the web UI and API, and the other one to handle all other tasks.
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
services:
|
services:
|
||||||
|
|||||||
21
docs/docs/developer/translations.md
Normal file
21
docs/docs/developer/translations.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# Translations
|
||||||
|
|
||||||
|
:::tip
|
||||||
|
You can request a new language [here](https://hosted.weblate.org/new-lang/immich/immich/).
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Weblate
|
||||||
|
|
||||||
|
[Weblate](https://weblate.org/) is a "libre software web-based continuous localization system". Immich localization efforts are managed on their [hosted platform](https://hosted.weblate.org/projects/immich/immich/).
|
||||||
|
|
||||||
|
## International message format
|
||||||
|
|
||||||
|
Plurals, numbers, dates and other locale specific message formats can be handled by using the [ICU message format](https://unicode-org.github.io/icu/userguide/format_parse/messages/). Internally, this is handled by the [intl-messageformat](https://www.npmjs.com/package/intl-messageformat) library. Their [documentation](https://formatjs.io/docs/intl-messageformat/) includes common, editable examples via a "live editor" feature, which can be useful to test and debug message formats.
|
||||||
|
|
||||||
|
## Progress
|
||||||
|
|
||||||
|
Immich currently supports the following languages:
|
||||||
|
|
||||||
|
<a href="https://hosted.weblate.org/engage/immich/">
|
||||||
|
<img src="https://hosted.weblate.org/widget/immich/immich/multi-auto.svg" alt="Translation status" />
|
||||||
|
</a>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
# Troubleshooting
|
# Troubleshooting
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
A great option to get assistance with troubleshooting is to join our [Discord](https://discord.gg/D8JsnBEuKb) server, where we have a dedicated channel for `#contributing`.
|
A great option to get assistance with troubleshooting is to join our [Discord](https://discord.immich.app) server, where we have a dedicated channel for `#contributing`.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
## Known Issues
|
## Known Issues
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ For more information about setting up the community image see [here](https://git
|
|||||||
|
|
||||||
:::info
|
:::info
|
||||||
|
|
||||||
- Guide was written using Unraid v6.12.10
|
- Guide was written using Unraid v6.12.10.
|
||||||
- Requires you to have installed the plugin: [Docker Compose Manager](https://forums.unraid.net/topic/114415-plugin-docker-compose-manager/)
|
- Requires you to have installed the plugin: [Docker Compose Manager](https://forums.unraid.net/topic/114415-plugin-docker-compose-manager/)
|
||||||
- An Unraid share created for your images
|
- An Unraid share created for your images
|
||||||
- There has been a [report](https://forums.unraid.net/topic/130006-errortraps-traps-node27707-trap-invalid-opcode-ip14fcfc8d03c0-sp7fff32889dd8-more/#comment-1189395) of this not working if your Unraid server doesn't support AVX _(e.g. using a T610)_
|
- There has been a [report](https://forums.unraid.net/topic/130006-errortraps-traps-node27707-trap-invalid-opcode-ip14fcfc8d03c0-sp7fff32889dd8-more/#comment-1189395) of this not working if your Unraid server doesn't support AVX _(e.g. using a T610)_
|
||||||
@@ -46,7 +46,8 @@ alt="Select Plugins > Compose.Manager > Add New Stack > Label it Immich"
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
3. Select the cog ⚙️ next to Immich then click "**Edit Stack**"
|
3. Select the cog ⚙️ next to Immich then click "**Edit Stack**"
|
||||||
4. Click "**Compose File**" and then paste the entire contents of the [Immich Docker Compose](https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml) file into the Unraid editor. Remove any text that may be in the text area by default.
|
4. Click "**Compose File**" and then paste the entire contents of the [Immich Docker Compose](https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml) file into the Unraid editor. Remove any text that may be in the text area by default. Note that Unraid v6.12.10 uses version 24.0.9 of the Docker Engine, which does not support healthcheck `start_interval` as defined in the `database` service of the Docker compose file (version 25 or higher is needed). This parameter defines an initial waiting period before starting health checks, to give the container time to start up. Commenting out the `start_interval` and `start_period` parameters will allow the containers to start up normally. The only downside to this is that the database container will not receive an initial health check until `interval` time has passed.
|
||||||
|
|
||||||
<details >
|
<details >
|
||||||
<summary>Using an existing Postgres container? Click me! Otherwise proceed to step 5.</summary>
|
<summary>Using an existing Postgres container? Click me! Otherwise proceed to step 5.</summary>
|
||||||
<ul>
|
<ul>
|
||||||
@@ -70,6 +71,7 @@ alt="Select Plugins > Compose.Manager > Add New Stack > Label it Immich"
|
|||||||
/>
|
/>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
5. Click "**Save Changes**", you will be promoted to edit stack UI labels, just leave this blank and click "**Ok**"
|
5. Click "**Save Changes**", you will be promoted to edit stack UI labels, just leave this blank and click "**Ok**"
|
||||||
6. Select the cog ⚙️ next to Immich, click "**Edit Stack**", then click "**Env File**"
|
6. Select the cog ⚙️ next to Immich, click "**Edit Stack**", then click "**Env File**"
|
||||||
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:
|
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:
|
||||||
|
|||||||
@@ -13,4 +13,4 @@ Running into an issue or have a question? Try the following:
|
|||||||
|
|
||||||
[github-issues]: https://github.com/immich-app/immich/issues
|
[github-issues]: https://github.com/immich-app/immich/issues
|
||||||
[github-releases]: https://github.com/immich-app/immich/releases
|
[github-releases]: https://github.com/immich-app/immich/releases
|
||||||
[discord-link]: https://discord.com/invite/D8JsnBEuKb
|
[discord-link]: https://discord.immich.app
|
||||||
|
|||||||
@@ -4,11 +4,17 @@ sidebar_position: 5
|
|||||||
|
|
||||||
# Support The Project
|
# Support The Project
|
||||||
|
|
||||||
## Contributing
|
## Report issues
|
||||||
|
|
||||||
1. Testing - Using Immich and reporting bugs is a great way to help support the project. Found a bug? [Open an issue on GitHub][github-issue].
|
By far the easiest way to help make Immich better it to use it and report issues and bugs. Found a bug? [Open an issue on GitHub][github-issue].
|
||||||
1. Translations - The Immich mobile app has been translated into [17 languages][github-langs] so far! To contribute with translations, email me at alex.tran1502@gmail.com or send me a message on discord.
|
|
||||||
1. Development - 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.
|
## Translations
|
||||||
|
|
||||||
|
Support the project by localizing on [Weblate](https://hosted.weblate.org/projects/immich/immich/). For more information, see the [Translations](/docs/developer/translations) section.
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
[github-issue]: https://github.com/immich-app/immich/issues/new/choose
|
[github-issue]: https://github.com/immich-app/immich/issues/new/choose
|
||||||
[github-langs]: https://github.com/immich-app/immich/tree/main/mobile/assets/i18n
|
[github-langs]: https://github.com/immich-app/immich/tree/main/mobile/assets/i18n
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ const config = {
|
|||||||
position: 'right',
|
position: 'right',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
href: 'https://discord.gg/D8JsnBEuKb',
|
href: 'https://discord.immich.app',
|
||||||
label: 'Discord',
|
label: 'Discord',
|
||||||
position: 'right',
|
position: 'right',
|
||||||
},
|
},
|
||||||
@@ -151,7 +151,7 @@ const config = {
|
|||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
label: 'Discord',
|
label: 'Discord',
|
||||||
href: 'https://discord.com/invite/D8JsnBEuKb',
|
href: 'https://discord.immich.app',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Reddit',
|
label: 'Reddit',
|
||||||
|
|||||||
363
docs/package-lock.json
generated
363
docs/package-lock.json
generated
@@ -2155,9 +2155,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/core": {
|
"node_modules/@docusaurus/core": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.4.0.tgz",
|
||||||
"integrity": "sha512-PzKMydKI3IU1LmeZQDi+ut5RSuilbXnA8QdowGeJEgU8EJjmx3rBHNT1LxQxOVqNEwpWi/csLwd9bn7rUjggPA==",
|
"integrity": "sha512-g+0wwmN2UJsBqy2fQRQ6fhXruoEa62JDeEa5d8IdTJlMoaDaEDfHh7WjwGRn4opuTQWpjAwP/fbcgyHKlE+64w==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "^7.23.3",
|
"@babel/core": "^7.23.3",
|
||||||
"@babel/generator": "^7.23.3",
|
"@babel/generator": "^7.23.3",
|
||||||
@@ -2169,12 +2170,12 @@
|
|||||||
"@babel/runtime": "^7.22.6",
|
"@babel/runtime": "^7.22.6",
|
||||||
"@babel/runtime-corejs3": "^7.22.6",
|
"@babel/runtime-corejs3": "^7.22.6",
|
||||||
"@babel/traverse": "^7.22.8",
|
"@babel/traverse": "^7.22.8",
|
||||||
"@docusaurus/cssnano-preset": "3.3.2",
|
"@docusaurus/cssnano-preset": "3.4.0",
|
||||||
"@docusaurus/logger": "3.3.2",
|
"@docusaurus/logger": "3.4.0",
|
||||||
"@docusaurus/mdx-loader": "3.3.2",
|
"@docusaurus/mdx-loader": "3.4.0",
|
||||||
"@docusaurus/utils": "3.3.2",
|
"@docusaurus/utils": "3.4.0",
|
||||||
"@docusaurus/utils-common": "3.3.2",
|
"@docusaurus/utils-common": "3.4.0",
|
||||||
"@docusaurus/utils-validation": "3.3.2",
|
"@docusaurus/utils-validation": "3.4.0",
|
||||||
"autoprefixer": "^10.4.14",
|
"autoprefixer": "^10.4.14",
|
||||||
"babel-loader": "^9.1.3",
|
"babel-loader": "^9.1.3",
|
||||||
"babel-plugin-dynamic-import-node": "^2.3.3",
|
"babel-plugin-dynamic-import-node": "^2.3.3",
|
||||||
@@ -2240,9 +2241,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/cssnano-preset": {
|
"node_modules/@docusaurus/cssnano-preset": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.4.0.tgz",
|
||||||
"integrity": "sha512-+5+epLk/Rp4vFML4zmyTATNc3Is+buMAL6dNjrMWahdJCJlMWMPd/8YfU+2PA57t8mlSbhLJ7vAZVy54cd1vRQ==",
|
"integrity": "sha512-qwLFSz6v/pZHy/UP32IrprmH5ORce86BGtN0eBtG75PpzQJAzp9gefspox+s8IEOr0oZKuQ/nhzZ3xwyc3jYJQ==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cssnano-preset-advanced": "^6.1.2",
|
"cssnano-preset-advanced": "^6.1.2",
|
||||||
"postcss": "^8.4.38",
|
"postcss": "^8.4.38",
|
||||||
@@ -2254,9 +2256,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/logger": {
|
"node_modules/@docusaurus/logger": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.4.0.tgz",
|
||||||
"integrity": "sha512-Ldu38GJ4P8g4guN7d7pyCOJ7qQugG7RVyaxrK8OnxuTlaImvQw33aDRwaX2eNmX8YK6v+//Z502F4sOZbHHCHQ==",
|
"integrity": "sha512-bZwkX+9SJ8lB9kVRkXw+xvHYSMGG4bpYHKGXeXFvyVc79NMeeBSGgzd4TQLHH+DYeOJoCdl8flrFJVxlZ0wo/Q==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chalk": "^4.1.2",
|
"chalk": "^4.1.2",
|
||||||
"tslib": "^2.6.0"
|
"tslib": "^2.6.0"
|
||||||
@@ -2266,13 +2269,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/mdx-loader": {
|
"node_modules/@docusaurus/mdx-loader": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.4.0.tgz",
|
||||||
"integrity": "sha512-AFRxj/aOk3/mfYDPxE3wTbrjeayVRvNSZP7mgMuUlrb2UlPRbSVAFX1k2RbgAJrnTSwMgb92m2BhJgYRfptN3g==",
|
"integrity": "sha512-kSSbrrk4nTjf4d+wtBA9H+FGauf2gCax89kV8SUSJu3qaTdSIKdWERlngsiHaCFgZ7laTJ8a67UFf+xlFPtuTw==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/logger": "3.3.2",
|
"@docusaurus/logger": "3.4.0",
|
||||||
"@docusaurus/utils": "3.3.2",
|
"@docusaurus/utils": "3.4.0",
|
||||||
"@docusaurus/utils-validation": "3.3.2",
|
"@docusaurus/utils-validation": "3.4.0",
|
||||||
"@mdx-js/mdx": "^3.0.0",
|
"@mdx-js/mdx": "^3.0.0",
|
||||||
"@slorber/remark-comment": "^1.0.0",
|
"@slorber/remark-comment": "^1.0.0",
|
||||||
"escape-html": "^1.0.3",
|
"escape-html": "^1.0.3",
|
||||||
@@ -2304,11 +2308,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/module-type-aliases": {
|
"node_modules/@docusaurus/module-type-aliases": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.4.0.tgz",
|
||||||
"integrity": "sha512-b/XB0TBJah5yKb4LYuJT4buFvL0MGAb0+vJDrJtlYMguRtsEBkf2nWl5xP7h4Dlw6ol0hsHrCYzJ50kNIOEclw==",
|
"integrity": "sha512-A1AyS8WF5Bkjnb8s+guTDuYmUiwJzNrtchebBHpc0gz0PyHJNMaybUlSrmJjHVcGrya0LKI4YcR3lBDQfXRYLw==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/types": "3.3.2",
|
"@docusaurus/types": "3.4.0",
|
||||||
"@types/history": "^4.7.11",
|
"@types/history": "^4.7.11",
|
||||||
"@types/react": "*",
|
"@types/react": "*",
|
||||||
"@types/react-router-config": "*",
|
"@types/react-router-config": "*",
|
||||||
@@ -2322,17 +2327,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/plugin-content-blog": {
|
"node_modules/@docusaurus/plugin-content-blog": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.4.0.tgz",
|
||||||
"integrity": "sha512-fJU+dmqp231LnwDJv+BHVWft8pcUS2xVPZdeYH6/ibH1s2wQ/sLcmUrGWyIv/Gq9Ptj8XWjRPMghlxghuPPoxg==",
|
"integrity": "sha512-vv6ZAj78ibR5Jh7XBUT4ndIjmlAxkijM3Sx5MAAzC1gyv0vupDQNhzuFg1USQmQVj3P5I6bquk12etPV3LJ+Xw==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "3.3.2",
|
"@docusaurus/core": "3.4.0",
|
||||||
"@docusaurus/logger": "3.3.2",
|
"@docusaurus/logger": "3.4.0",
|
||||||
"@docusaurus/mdx-loader": "3.3.2",
|
"@docusaurus/mdx-loader": "3.4.0",
|
||||||
"@docusaurus/types": "3.3.2",
|
"@docusaurus/types": "3.4.0",
|
||||||
"@docusaurus/utils": "3.3.2",
|
"@docusaurus/utils": "3.4.0",
|
||||||
"@docusaurus/utils-common": "3.3.2",
|
"@docusaurus/utils-common": "3.4.0",
|
||||||
"@docusaurus/utils-validation": "3.3.2",
|
"@docusaurus/utils-validation": "3.4.0",
|
||||||
"cheerio": "^1.0.0-rc.12",
|
"cheerio": "^1.0.0-rc.12",
|
||||||
"feed": "^4.2.2",
|
"feed": "^4.2.2",
|
||||||
"fs-extra": "^11.1.1",
|
"fs-extra": "^11.1.1",
|
||||||
@@ -2353,18 +2359,19 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/plugin-content-docs": {
|
"node_modules/@docusaurus/plugin-content-docs": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.4.0.tgz",
|
||||||
"integrity": "sha512-Dm1ri2VlGATTN3VGk1ZRqdRXWa1UlFubjaEL6JaxaK7IIFqN/Esjpl+Xw10R33loHcRww/H76VdEeYayaL76eg==",
|
"integrity": "sha512-HkUCZffhBo7ocYheD9oZvMcDloRnGhBMOZRyVcAQRFmZPmNqSyISlXA1tQCIxW+r478fty97XXAGjNYzBjpCsg==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "3.3.2",
|
"@docusaurus/core": "3.4.0",
|
||||||
"@docusaurus/logger": "3.3.2",
|
"@docusaurus/logger": "3.4.0",
|
||||||
"@docusaurus/mdx-loader": "3.3.2",
|
"@docusaurus/mdx-loader": "3.4.0",
|
||||||
"@docusaurus/module-type-aliases": "3.3.2",
|
"@docusaurus/module-type-aliases": "3.4.0",
|
||||||
"@docusaurus/types": "3.3.2",
|
"@docusaurus/types": "3.4.0",
|
||||||
"@docusaurus/utils": "3.3.2",
|
"@docusaurus/utils": "3.4.0",
|
||||||
"@docusaurus/utils-common": "3.3.2",
|
"@docusaurus/utils-common": "3.4.0",
|
||||||
"@docusaurus/utils-validation": "3.3.2",
|
"@docusaurus/utils-validation": "3.4.0",
|
||||||
"@types/react-router-config": "^5.0.7",
|
"@types/react-router-config": "^5.0.7",
|
||||||
"combine-promises": "^1.1.0",
|
"combine-promises": "^1.1.0",
|
||||||
"fs-extra": "^11.1.1",
|
"fs-extra": "^11.1.1",
|
||||||
@@ -2383,15 +2390,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/plugin-content-pages": {
|
"node_modules/@docusaurus/plugin-content-pages": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.4.0.tgz",
|
||||||
"integrity": "sha512-EKc9fQn5H2+OcGER8x1aR+7URtAGWySUgULfqE/M14+rIisdrBstuEZ4lUPDRrSIexOVClML82h2fDS+GSb8Ew==",
|
"integrity": "sha512-h2+VN/0JjpR8fIkDEAoadNjfR3oLzB+v1qSXbIAKjQ46JAHx3X22n9nqS+BWSQnTnp1AjkjSvZyJMekmcwxzxg==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "3.3.2",
|
"@docusaurus/core": "3.4.0",
|
||||||
"@docusaurus/mdx-loader": "3.3.2",
|
"@docusaurus/mdx-loader": "3.4.0",
|
||||||
"@docusaurus/types": "3.3.2",
|
"@docusaurus/types": "3.4.0",
|
||||||
"@docusaurus/utils": "3.3.2",
|
"@docusaurus/utils": "3.4.0",
|
||||||
"@docusaurus/utils-validation": "3.3.2",
|
"@docusaurus/utils-validation": "3.4.0",
|
||||||
"fs-extra": "^11.1.1",
|
"fs-extra": "^11.1.1",
|
||||||
"tslib": "^2.6.0",
|
"tslib": "^2.6.0",
|
||||||
"webpack": "^5.88.1"
|
"webpack": "^5.88.1"
|
||||||
@@ -2405,13 +2413,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/plugin-debug": {
|
"node_modules/@docusaurus/plugin-debug": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.4.0.tgz",
|
||||||
"integrity": "sha512-oBIBmwtaB+YS0XlmZ3gCO+cMbsGvIYuAKkAopoCh0arVjtlyPbejzPrHuCoRHB9G7abjNZw7zoONOR8+8LM5+Q==",
|
"integrity": "sha512-uV7FDUNXGyDSD3PwUaf5YijX91T5/H9SX4ErEcshzwgzWwBtK37nUWPU3ZLJfeTavX3fycTOqk9TglpOLaWkCg==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "3.3.2",
|
"@docusaurus/core": "3.4.0",
|
||||||
"@docusaurus/types": "3.3.2",
|
"@docusaurus/types": "3.4.0",
|
||||||
"@docusaurus/utils": "3.3.2",
|
"@docusaurus/utils": "3.4.0",
|
||||||
"fs-extra": "^11.1.1",
|
"fs-extra": "^11.1.1",
|
||||||
"react-json-view-lite": "^1.2.0",
|
"react-json-view-lite": "^1.2.0",
|
||||||
"tslib": "^2.6.0"
|
"tslib": "^2.6.0"
|
||||||
@@ -2425,13 +2434,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/plugin-google-analytics": {
|
"node_modules/@docusaurus/plugin-google-analytics": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.4.0.tgz",
|
||||||
"integrity": "sha512-jXhrEIhYPSClMBK6/IA8qf1/FBoxqGXZvg7EuBax9HaK9+kL3L0TJIlatd8jQJOMtds8mKw806TOCc3rtEad1A==",
|
"integrity": "sha512-mCArluxEGi3cmYHqsgpGGt3IyLCrFBxPsxNZ56Mpur0xSlInnIHoeLDH7FvVVcPJRPSQ9/MfRqLsainRw+BojA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "3.3.2",
|
"@docusaurus/core": "3.4.0",
|
||||||
"@docusaurus/types": "3.3.2",
|
"@docusaurus/types": "3.4.0",
|
||||||
"@docusaurus/utils-validation": "3.3.2",
|
"@docusaurus/utils-validation": "3.4.0",
|
||||||
"tslib": "^2.6.0"
|
"tslib": "^2.6.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2443,13 +2453,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/plugin-google-gtag": {
|
"node_modules/@docusaurus/plugin-google-gtag": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.4.0.tgz",
|
||||||
"integrity": "sha512-vcrKOHGbIDjVnNMrfbNpRQR1x6Jvcrb48kVzpBAOsKbj9rXZm/idjVAXRaewwobHdOrJkfWS/UJoxzK8wyLRBQ==",
|
"integrity": "sha512-Dsgg6PLAqzZw5wZ4QjUYc8Z2KqJqXxHxq3vIoyoBWiLEEfigIs7wHR+oiWUQy3Zk9MIk6JTYj7tMoQU0Jm3nqA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "3.3.2",
|
"@docusaurus/core": "3.4.0",
|
||||||
"@docusaurus/types": "3.3.2",
|
"@docusaurus/types": "3.4.0",
|
||||||
"@docusaurus/utils-validation": "3.3.2",
|
"@docusaurus/utils-validation": "3.4.0",
|
||||||
"@types/gtag.js": "^0.0.12",
|
"@types/gtag.js": "^0.0.12",
|
||||||
"tslib": "^2.6.0"
|
"tslib": "^2.6.0"
|
||||||
},
|
},
|
||||||
@@ -2462,13 +2473,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/plugin-google-tag-manager": {
|
"node_modules/@docusaurus/plugin-google-tag-manager": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.4.0.tgz",
|
||||||
"integrity": "sha512-ldkR58Fdeks0vC+HQ+L+bGFSJsotQsipXD+iKXQFvkOfmPIV6QbHRd7IIcm5b6UtwOiK33PylNS++gjyLUmaGw==",
|
"integrity": "sha512-O9tX1BTwxIhgXpOLpFDueYA9DWk69WCbDRrjYoMQtFHSkTyE7RhNgyjSPREUWJb9i+YUg3OrsvrBYRl64FCPCQ==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "3.3.2",
|
"@docusaurus/core": "3.4.0",
|
||||||
"@docusaurus/types": "3.3.2",
|
"@docusaurus/types": "3.4.0",
|
||||||
"@docusaurus/utils-validation": "3.3.2",
|
"@docusaurus/utils-validation": "3.4.0",
|
||||||
"tslib": "^2.6.0"
|
"tslib": "^2.6.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2480,16 +2492,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/plugin-sitemap": {
|
"node_modules/@docusaurus/plugin-sitemap": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.4.0.tgz",
|
||||||
"integrity": "sha512-/ZI1+bwZBhAgC30inBsHe3qY9LOZS+79fRGkNdTcGHRMcdAp6Vw2pCd1gzlxd/xU+HXsNP6cLmTOrggmRp3Ujg==",
|
"integrity": "sha512-+0VDvx9SmNrFNgwPoeoCha+tRoAjopwT0+pYO1xAbyLcewXSemq+eLxEa46Q1/aoOaJQ0qqHELuQM7iS2gp33Q==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "3.3.2",
|
"@docusaurus/core": "3.4.0",
|
||||||
"@docusaurus/logger": "3.3.2",
|
"@docusaurus/logger": "3.4.0",
|
||||||
"@docusaurus/types": "3.3.2",
|
"@docusaurus/types": "3.4.0",
|
||||||
"@docusaurus/utils": "3.3.2",
|
"@docusaurus/utils": "3.4.0",
|
||||||
"@docusaurus/utils-common": "3.3.2",
|
"@docusaurus/utils-common": "3.4.0",
|
||||||
"@docusaurus/utils-validation": "3.3.2",
|
"@docusaurus/utils-validation": "3.4.0",
|
||||||
"fs-extra": "^11.1.1",
|
"fs-extra": "^11.1.1",
|
||||||
"sitemap": "^7.1.1",
|
"sitemap": "^7.1.1",
|
||||||
"tslib": "^2.6.0"
|
"tslib": "^2.6.0"
|
||||||
@@ -2503,23 +2516,24 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/preset-classic": {
|
"node_modules/@docusaurus/preset-classic": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.4.0.tgz",
|
||||||
"integrity": "sha512-1SDS7YIUN1Pg3BmD6TOTjhB7RSBHJRpgIRKx9TpxqyDrJ92sqtZhomDc6UYoMMLQNF2wHFZZVGFjxJhw2VpL+Q==",
|
"integrity": "sha512-Ohj6KB7siKqZaQhNJVMBBUzT3Nnp6eTKqO+FXO3qu/n1hJl3YLwVKTWBg28LF7MWrKu46UuYavwMRxud0VyqHg==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "3.3.2",
|
"@docusaurus/core": "3.4.0",
|
||||||
"@docusaurus/plugin-content-blog": "3.3.2",
|
"@docusaurus/plugin-content-blog": "3.4.0",
|
||||||
"@docusaurus/plugin-content-docs": "3.3.2",
|
"@docusaurus/plugin-content-docs": "3.4.0",
|
||||||
"@docusaurus/plugin-content-pages": "3.3.2",
|
"@docusaurus/plugin-content-pages": "3.4.0",
|
||||||
"@docusaurus/plugin-debug": "3.3.2",
|
"@docusaurus/plugin-debug": "3.4.0",
|
||||||
"@docusaurus/plugin-google-analytics": "3.3.2",
|
"@docusaurus/plugin-google-analytics": "3.4.0",
|
||||||
"@docusaurus/plugin-google-gtag": "3.3.2",
|
"@docusaurus/plugin-google-gtag": "3.4.0",
|
||||||
"@docusaurus/plugin-google-tag-manager": "3.3.2",
|
"@docusaurus/plugin-google-tag-manager": "3.4.0",
|
||||||
"@docusaurus/plugin-sitemap": "3.3.2",
|
"@docusaurus/plugin-sitemap": "3.4.0",
|
||||||
"@docusaurus/theme-classic": "3.3.2",
|
"@docusaurus/theme-classic": "3.4.0",
|
||||||
"@docusaurus/theme-common": "3.3.2",
|
"@docusaurus/theme-common": "3.4.0",
|
||||||
"@docusaurus/theme-search-algolia": "3.3.2",
|
"@docusaurus/theme-search-algolia": "3.4.0",
|
||||||
"@docusaurus/types": "3.3.2"
|
"@docusaurus/types": "3.4.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0"
|
"node": ">=18.0"
|
||||||
@@ -2530,22 +2544,23 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/theme-classic": {
|
"node_modules/@docusaurus/theme-classic": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.4.0.tgz",
|
||||||
"integrity": "sha512-gepHFcsluIkPb4Im9ukkiO4lXrai671wzS3cKQkY9BXQgdVwsdPf/KS0Vs4Xlb0F10fTz+T3gNjkxNEgSN9M0A==",
|
"integrity": "sha512-0IPtmxsBYv2adr1GnZRdMkEQt1YW6tpzrUPj02YxNpvJ5+ju4E13J5tB4nfdaen/tfR1hmpSPlTFPvTf4kwy8Q==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "3.3.2",
|
"@docusaurus/core": "3.4.0",
|
||||||
"@docusaurus/mdx-loader": "3.3.2",
|
"@docusaurus/mdx-loader": "3.4.0",
|
||||||
"@docusaurus/module-type-aliases": "3.3.2",
|
"@docusaurus/module-type-aliases": "3.4.0",
|
||||||
"@docusaurus/plugin-content-blog": "3.3.2",
|
"@docusaurus/plugin-content-blog": "3.4.0",
|
||||||
"@docusaurus/plugin-content-docs": "3.3.2",
|
"@docusaurus/plugin-content-docs": "3.4.0",
|
||||||
"@docusaurus/plugin-content-pages": "3.3.2",
|
"@docusaurus/plugin-content-pages": "3.4.0",
|
||||||
"@docusaurus/theme-common": "3.3.2",
|
"@docusaurus/theme-common": "3.4.0",
|
||||||
"@docusaurus/theme-translations": "3.3.2",
|
"@docusaurus/theme-translations": "3.4.0",
|
||||||
"@docusaurus/types": "3.3.2",
|
"@docusaurus/types": "3.4.0",
|
||||||
"@docusaurus/utils": "3.3.2",
|
"@docusaurus/utils": "3.4.0",
|
||||||
"@docusaurus/utils-common": "3.3.2",
|
"@docusaurus/utils-common": "3.4.0",
|
||||||
"@docusaurus/utils-validation": "3.3.2",
|
"@docusaurus/utils-validation": "3.4.0",
|
||||||
"@mdx-js/react": "^3.0.0",
|
"@mdx-js/react": "^3.0.0",
|
||||||
"clsx": "^2.0.0",
|
"clsx": "^2.0.0",
|
||||||
"copy-text-to-clipboard": "^3.2.0",
|
"copy-text-to-clipboard": "^3.2.0",
|
||||||
@@ -2569,17 +2584,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/theme-common": {
|
"node_modules/@docusaurus/theme-common": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.4.0.tgz",
|
||||||
"integrity": "sha512-kXqSaL/sQqo4uAMQ4fHnvRZrH45Xz2OdJ3ABXDS7YVGPSDTBC8cLebFrRR4YF9EowUHto1UC/EIklJZQMG/usA==",
|
"integrity": "sha512-0A27alXuv7ZdCg28oPE8nH/Iz73/IUejVaCazqu9elS4ypjiLhK3KfzdSQBnL/g7YfHSlymZKdiOHEo8fJ0qMA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/mdx-loader": "3.3.2",
|
"@docusaurus/mdx-loader": "3.4.0",
|
||||||
"@docusaurus/module-type-aliases": "3.3.2",
|
"@docusaurus/module-type-aliases": "3.4.0",
|
||||||
"@docusaurus/plugin-content-blog": "3.3.2",
|
"@docusaurus/plugin-content-blog": "3.4.0",
|
||||||
"@docusaurus/plugin-content-docs": "3.3.2",
|
"@docusaurus/plugin-content-docs": "3.4.0",
|
||||||
"@docusaurus/plugin-content-pages": "3.3.2",
|
"@docusaurus/plugin-content-pages": "3.4.0",
|
||||||
"@docusaurus/utils": "3.3.2",
|
"@docusaurus/utils": "3.4.0",
|
||||||
"@docusaurus/utils-common": "3.3.2",
|
"@docusaurus/utils-common": "3.4.0",
|
||||||
"@types/history": "^4.7.11",
|
"@types/history": "^4.7.11",
|
||||||
"@types/react": "*",
|
"@types/react": "*",
|
||||||
"@types/react-router-config": "*",
|
"@types/react-router-config": "*",
|
||||||
@@ -2598,18 +2614,19 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/theme-search-algolia": {
|
"node_modules/@docusaurus/theme-search-algolia": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.4.0.tgz",
|
||||||
"integrity": "sha512-qLkfCl29VNBnF1MWiL9IyOQaHxUvicZp69hISyq/xMsNvFKHFOaOfk9xezYod2Q9xx3xxUh9t/QPigIei2tX4w==",
|
"integrity": "sha512-aiHFx7OCw4Wck1z6IoShVdUWIjntC8FHCw9c5dR8r3q4Ynh+zkS8y2eFFunN/DL6RXPzpnvKCg3vhLQYJDmT9Q==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docsearch/react": "^3.5.2",
|
"@docsearch/react": "^3.5.2",
|
||||||
"@docusaurus/core": "3.3.2",
|
"@docusaurus/core": "3.4.0",
|
||||||
"@docusaurus/logger": "3.3.2",
|
"@docusaurus/logger": "3.4.0",
|
||||||
"@docusaurus/plugin-content-docs": "3.3.2",
|
"@docusaurus/plugin-content-docs": "3.4.0",
|
||||||
"@docusaurus/theme-common": "3.3.2",
|
"@docusaurus/theme-common": "3.4.0",
|
||||||
"@docusaurus/theme-translations": "3.3.2",
|
"@docusaurus/theme-translations": "3.4.0",
|
||||||
"@docusaurus/utils": "3.3.2",
|
"@docusaurus/utils": "3.4.0",
|
||||||
"@docusaurus/utils-validation": "3.3.2",
|
"@docusaurus/utils-validation": "3.4.0",
|
||||||
"algoliasearch": "^4.18.0",
|
"algoliasearch": "^4.18.0",
|
||||||
"algoliasearch-helper": "^3.13.3",
|
"algoliasearch-helper": "^3.13.3",
|
||||||
"clsx": "^2.0.0",
|
"clsx": "^2.0.0",
|
||||||
@@ -2628,9 +2645,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/theme-translations": {
|
"node_modules/@docusaurus/theme-translations": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.4.0.tgz",
|
||||||
"integrity": "sha512-bPuiUG7Z8sNpGuTdGnmKl/oIPeTwKr0AXLGu9KaP6+UFfRZiyWbWE87ti97RrevB2ffojEdvchNujparR3jEZQ==",
|
"integrity": "sha512-zSxCSpmQCCdQU5Q4CnX/ID8CSUUI3fvmq4hU/GNP/XoAWtXo9SAVnM3TzpU8Gb//H3WCsT8mJcTfyOk3d9ftNg==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fs-extra": "^11.1.1",
|
"fs-extra": "^11.1.1",
|
||||||
"tslib": "^2.6.0"
|
"tslib": "^2.6.0"
|
||||||
@@ -2640,9 +2658,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/types": {
|
"node_modules/@docusaurus/types": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.4.0.tgz",
|
||||||
"integrity": "sha512-5p201S7AZhliRxTU7uMKtSsoC8mgPA9bs9b5NQg1IRdRxJfflursXNVsgc3PcMqiUTul/v1s3k3rXXFlRE890w==",
|
"integrity": "sha512-4jcDO8kXi5Cf9TcyikB/yKmz14f2RZ2qTRerbHAsS+5InE9ZgSLBNLsewtFTcTOXSVcbU3FoGOzcNWAmU1TR0A==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mdx-js/mdx": "^3.0.0",
|
"@mdx-js/mdx": "^3.0.0",
|
||||||
"@types/history": "^4.7.11",
|
"@types/history": "^4.7.11",
|
||||||
@@ -2660,12 +2679,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/utils": {
|
"node_modules/@docusaurus/utils": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.4.0.tgz",
|
||||||
"integrity": "sha512-f4YMnBVymtkSxONv4Y8js3Gez9IgHX+Lcg6YRMOjVbq8sgCcdYK1lf6SObAuz5qB/mxiSK7tW0M9aaiIaUSUJg==",
|
"integrity": "sha512-fRwnu3L3nnWaXOgs88BVBmG1yGjcQqZNHG+vInhEa2Sz2oQB+ZjbEMO5Rh9ePFpZ0YDiDUhpaVjwmS+AU2F14g==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/logger": "3.3.2",
|
"@docusaurus/logger": "3.4.0",
|
||||||
"@docusaurus/utils-common": "3.3.2",
|
"@docusaurus/utils-common": "3.4.0",
|
||||||
"@svgr/webpack": "^8.1.0",
|
"@svgr/webpack": "^8.1.0",
|
||||||
"escape-string-regexp": "^4.0.0",
|
"escape-string-regexp": "^4.0.0",
|
||||||
"file-loader": "^6.2.0",
|
"file-loader": "^6.2.0",
|
||||||
@@ -2682,6 +2702,7 @@
|
|||||||
"shelljs": "^0.8.5",
|
"shelljs": "^0.8.5",
|
||||||
"tslib": "^2.6.0",
|
"tslib": "^2.6.0",
|
||||||
"url-loader": "^4.1.1",
|
"url-loader": "^4.1.1",
|
||||||
|
"utility-types": "^3.10.0",
|
||||||
"webpack": "^5.88.1"
|
"webpack": "^5.88.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2697,9 +2718,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/utils-common": {
|
"node_modules/@docusaurus/utils-common": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.4.0.tgz",
|
||||||
"integrity": "sha512-QWFTLEkPYsejJsLStgtmetMFIA3pM8EPexcZ4WZ7b++gO5jGVH7zsipREnCHzk6+eDgeaXfkR6UPaTt86bp8Og==",
|
"integrity": "sha512-NVx54Wr4rCEKsjOH5QEVvxIqVvm+9kh7q8aYTU5WzUU9/Hctd6aTrcZ3G0Id4zYJ+AeaG5K5qHA4CY5Kcm2iyQ==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tslib": "^2.6.0"
|
"tslib": "^2.6.0"
|
||||||
},
|
},
|
||||||
@@ -2716,15 +2738,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@docusaurus/utils-validation": {
|
"node_modules/@docusaurus/utils-validation": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.4.0.tgz",
|
||||||
"integrity": "sha512-itDgFs5+cbW9REuC7NdXals4V6++KifgVMzoGOOOSIifBQw+8ULhy86u5e1lnptVL0sv8oAjq2alO7I40GR7pA==",
|
"integrity": "sha512-hYQ9fM+AXYVTWxJOT1EuNaRnrR2WGpRdLDQG07O8UOpsvCPWUVOeo26Rbm0JWY2sGLfzAb+tvJ62yF+8F+TV0g==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/logger": "3.3.2",
|
"@docusaurus/logger": "3.4.0",
|
||||||
"@docusaurus/utils": "3.3.2",
|
"@docusaurus/utils": "3.4.0",
|
||||||
"@docusaurus/utils-common": "3.3.2",
|
"@docusaurus/utils-common": "3.4.0",
|
||||||
|
"fs-extra": "^11.2.0",
|
||||||
"joi": "^17.9.2",
|
"joi": "^17.9.2",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
"tslib": "^2.6.0"
|
"tslib": "^2.6.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -13573,10 +13598,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prettier": {
|
"node_modules/prettier": {
|
||||||
"version": "3.2.5",
|
"version": "3.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz",
|
||||||
"integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==",
|
"integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"prettier": "bin/prettier.cjs"
|
"prettier": "bin/prettier.cjs"
|
||||||
},
|
},
|
||||||
@@ -15986,9 +16012,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tailwindcss": {
|
"node_modules/tailwindcss": {
|
||||||
"version": "3.4.3",
|
"version": "3.4.4",
|
||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.4.tgz",
|
||||||
"integrity": "sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==",
|
"integrity": "sha512-ZoyXOdJjISB7/BcLTR6SEsLgKtDStYyYZVLsUtWChO4Ps20CBad7lfJKVDiejocV4ME1hLmyY0WJE3hSDcmQ2A==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@alloc/quick-lru": "^5.2.0",
|
"@alloc/quick-lru": "^5.2.0",
|
||||||
"arg": "^5.0.2",
|
"arg": "^5.0.2",
|
||||||
@@ -16025,6 +16052,7 @@
|
|||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
||||||
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
|
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
|
||||||
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"is-glob": "^4.0.3"
|
"is-glob": "^4.0.3"
|
||||||
},
|
},
|
||||||
@@ -16346,9 +16374,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript": {
|
"node_modules/typescript": {
|
||||||
"version": "5.4.5",
|
"version": "5.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.2.tgz",
|
||||||
"integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
|
"integrity": "sha512-NcRtPEOsPFFWjobJEtfihkLCZCXZt/os3zf8nTxjVH3RvTSxjrCamJpbExGvYOF+tFHc3pA65qpdwPbzjohhew==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
|
|||||||
@@ -56,6 +56,6 @@
|
|||||||
"node": ">=20"
|
"node": ">=20"
|
||||||
},
|
},
|
||||||
"volta": {
|
"volta": {
|
||||||
"node": "20.14.0"
|
"node": "20.15.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,11 @@ const guides: CommunityGuidesProps[] = [
|
|||||||
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',
|
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',
|
||||||
|
url: 'https://github.com/ppr88/immich-guides/blob/main/open-immich-custom-domain.md',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
function CommunityGuide({ title, description, url }: CommunityGuidesProps): JSX.Element {
|
function CommunityGuide({ title, description, url }: CommunityGuidesProps): JSX.Element {
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ function HomepageHeader() {
|
|||||||
|
|
||||||
<Link
|
<Link
|
||||||
className="flex place-items-center place-content-center py-3 px-8 border bg-immich-dark-primary dark:bg-immich-primary rounded-full hover:no-underline text-immich-primary dark:text-immich-dark-bg font-bold uppercase"
|
className="flex place-items-center place-content-center py-3 px-8 border bg-immich-dark-primary dark:bg-immich-primary rounded-full hover:no-underline text-immich-primary dark:text-immich-dark-bg font-bold uppercase"
|
||||||
to="https://discord.gg/D8JsnBEuKb"
|
to="https://discord.immich.app"
|
||||||
>
|
>
|
||||||
Discord
|
Discord
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
mdiCheckboxMarked,
|
mdiCheckboxMarked,
|
||||||
mdiCloudUploadOutline,
|
mdiCloudUploadOutline,
|
||||||
mdiCollage,
|
mdiCollage,
|
||||||
|
mdiContentDuplicate,
|
||||||
mdiDevices,
|
mdiDevices,
|
||||||
mdiEmailOutline,
|
mdiEmailOutline,
|
||||||
mdiExpansionCard,
|
mdiExpansionCard,
|
||||||
@@ -28,12 +29,14 @@ import {
|
|||||||
mdiForum,
|
mdiForum,
|
||||||
mdiHandshakeOutline,
|
mdiHandshakeOutline,
|
||||||
mdiHeart,
|
mdiHeart,
|
||||||
|
mdiHistory,
|
||||||
mdiImage,
|
mdiImage,
|
||||||
mdiImageAlbum,
|
mdiImageAlbum,
|
||||||
mdiImageEdit,
|
mdiImageEdit,
|
||||||
mdiImageMultipleOutline,
|
mdiImageMultipleOutline,
|
||||||
mdiImageSearch,
|
mdiImageSearch,
|
||||||
mdiKeyboardSettingsOutline,
|
mdiKeyboardSettingsOutline,
|
||||||
|
mdiLockOutline,
|
||||||
mdiMagnify,
|
mdiMagnify,
|
||||||
mdiMagnifyScan,
|
mdiMagnifyScan,
|
||||||
mdiMap,
|
mdiMap,
|
||||||
@@ -63,14 +66,13 @@ import {
|
|||||||
mdiVectorCombine,
|
mdiVectorCombine,
|
||||||
mdiVideo,
|
mdiVideo,
|
||||||
mdiWeb,
|
mdiWeb,
|
||||||
mdiContentDuplicate,
|
|
||||||
} from '@mdi/js';
|
} from '@mdi/js';
|
||||||
import Layout from '@theme/Layout';
|
import Layout from '@theme/Layout';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Item, Timeline } from '../components/timeline';
|
import { Item, Timeline } from '../components/timeline';
|
||||||
|
|
||||||
const releases = {
|
const releases = {
|
||||||
'v1.106.0': new Date(2024, 5, 11),
|
'v1.106.1': new Date(2024, 5, 11),
|
||||||
'v1.104.0': new Date(2024, 4, 13),
|
'v1.104.0': new Date(2024, 4, 13),
|
||||||
'v1.103.0': new Date(2024, 3, 29),
|
'v1.103.0': new Date(2024, 3, 29),
|
||||||
'v1.102.0': new Date(2024, 3, 15),
|
'v1.102.0': new Date(2024, 3, 15),
|
||||||
@@ -159,6 +161,14 @@ const withRelease = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const roadmap: Item[] = [
|
const roadmap: Item[] = [
|
||||||
|
{
|
||||||
|
done: false,
|
||||||
|
icon: mdiLockOutline,
|
||||||
|
iconColor: 'sandybrown',
|
||||||
|
title: 'Private/locked photos',
|
||||||
|
description: 'Private assets with extra protections',
|
||||||
|
getDateLabel: () => 'Planned for 2024',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
done: false,
|
done: false,
|
||||||
icon: mdiRocketLaunch,
|
icon: mdiRocketLaunch,
|
||||||
@@ -199,14 +209,6 @@ const roadmap: Item[] = [
|
|||||||
description: 'Granular access controls for users and api keys',
|
description: 'Granular access controls for users and api keys',
|
||||||
getDateLabel: () => 'Planned for 2024',
|
getDateLabel: () => 'Planned for 2024',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
done: false,
|
|
||||||
icon: mdiWeb,
|
|
||||||
iconColor: 'royalblue',
|
|
||||||
title: 'Web translations',
|
|
||||||
description: 'Translate the web application to multiple languages',
|
|
||||||
getDateLabel: () => 'Planned for 2024',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
done: false,
|
done: false,
|
||||||
icon: mdiCameraBurst,
|
icon: mdiCameraBurst,
|
||||||
@@ -218,18 +220,31 @@ const roadmap: Item[] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const milestones: Item[] = [
|
const milestones: Item[] = [
|
||||||
|
withRelease({
|
||||||
|
icon: mdiHistory,
|
||||||
|
title: 'Versioned documentation',
|
||||||
|
description: 'View documentation as it was at the time of past releases',
|
||||||
|
release: 'v1.106.1',
|
||||||
|
}),
|
||||||
|
withRelease({
|
||||||
|
icon: mdiWeb,
|
||||||
|
iconColor: 'royalblue',
|
||||||
|
title: 'Web translations',
|
||||||
|
description: 'Translate the web application to multiple languages',
|
||||||
|
release: 'v1.106.1',
|
||||||
|
}),
|
||||||
withRelease({
|
withRelease({
|
||||||
icon: mdiContentDuplicate,
|
icon: mdiContentDuplicate,
|
||||||
title: 'Similar image detection',
|
title: 'Similar image detection',
|
||||||
description: 'Detect duplicate assets that aren’t exactly identical',
|
description: 'Detect duplicate assets that aren’t exactly identical',
|
||||||
release: 'v1.106.0',
|
release: 'v1.106.1',
|
||||||
}),
|
}),
|
||||||
withRelease({
|
withRelease({
|
||||||
icon: mdiVectorCombine,
|
icon: mdiVectorCombine,
|
||||||
title: 'Container consolidation',
|
title: 'Container consolidation',
|
||||||
description:
|
description:
|
||||||
'The microservices container can be run as a worker within the server image, allowing us to remove it from the default stack.',
|
'The microservices container can be run as a worker within the server image, allowing us to remove it from the default stack.',
|
||||||
release: 'v1.106.0',
|
release: 'v1.106.1',
|
||||||
}),
|
}),
|
||||||
withRelease({
|
withRelease({
|
||||||
icon: mdiPencil,
|
icon: mdiPencil,
|
||||||
|
|||||||
12
docs/static/archived-versions.json
vendored
12
docs/static/archived-versions.json
vendored
@@ -1,4 +1,16 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"label": "v1.107.2",
|
||||||
|
"url": "https://v1.107.2.archive.immich.app"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "v1.107.1",
|
||||||
|
"url": "https://v1.107.1.archive.immich.app"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "v1.107.0",
|
||||||
|
"url": "https://v1.107.0.archive.immich.app"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"label": "v1.106.4",
|
"label": "v1.106.4",
|
||||||
"url": "https://v1.106.4.archive.immich.app"
|
"url": "https://v1.106.4.archive.immich.app"
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
20.14
|
20.15
|
||||||
|
|||||||
@@ -10,6 +10,11 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: ../
|
context: ../
|
||||||
dockerfile: server/Dockerfile
|
dockerfile: server/Dockerfile
|
||||||
|
args:
|
||||||
|
- BUILD_ID=1234567890
|
||||||
|
- BUILD_IMAGE=e2e
|
||||||
|
- BUILD_SOURCE_REF=e2e
|
||||||
|
- BUILD_SOURCE_COMMIT=e2eeeeeeeeeeeeeeeeee
|
||||||
environment:
|
environment:
|
||||||
- DB_HOSTNAME=database
|
- DB_HOSTNAME=database
|
||||||
- DB_USERNAME=postgres
|
- DB_USERNAME=postgres
|
||||||
@@ -17,6 +22,7 @@ services:
|
|||||||
- DB_DATABASE_NAME=immich
|
- DB_DATABASE_NAME=immich
|
||||||
- IMMICH_MACHINE_LEARNING_ENABLED=false
|
- IMMICH_MACHINE_LEARNING_ENABLED=false
|
||||||
- IMMICH_METRICS=true
|
- IMMICH_METRICS=true
|
||||||
|
- IMMICH_ENV=testing
|
||||||
volumes:
|
volumes:
|
||||||
- upload:/usr/src/app/upload
|
- upload:/usr/src/app/upload
|
||||||
- ./test-assets:/test-assets
|
- ./test-assets:/test-assets
|
||||||
@@ -27,7 +33,7 @@ services:
|
|||||||
- 2283:3001
|
- 2283:3001
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
image: redis:6.2-alpine@sha256:d6c2911ac51b289db208767581a5d154544f2b2fe4914ea5056443f62dc6e900
|
image: redis:6.2-alpine@sha256:328fe6a5822256d065debb36617a8169dbfbd77b797c525288e465f56c1d392b
|
||||||
|
|
||||||
database:
|
database:
|
||||||
image: tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0
|
image: tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0
|
||||||
|
|||||||
222
e2e/package-lock.json
generated
222
e2e/package-lock.json
generated
@@ -1,19 +1,19 @@
|
|||||||
{
|
{
|
||||||
"name": "immich-e2e",
|
"name": "immich-e2e",
|
||||||
"version": "1.106.4",
|
"version": "1.107.2",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "immich-e2e",
|
"name": "immich-e2e",
|
||||||
"version": "1.106.4",
|
"version": "1.107.2",
|
||||||
"license": "GNU Affero General Public License version 3",
|
"license": "GNU Affero General Public License version 3",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@immich/cli": "file:../cli",
|
"@immich/cli": "file:../cli",
|
||||||
"@immich/sdk": "file:../open-api/typescript-sdk",
|
"@immich/sdk": "file:../open-api/typescript-sdk",
|
||||||
"@playwright/test": "^1.44.1",
|
"@playwright/test": "^1.44.1",
|
||||||
"@types/luxon": "^3.4.2",
|
"@types/luxon": "^3.4.2",
|
||||||
"@types/node": "^20.11.17",
|
"@types/node": "^20.14.9",
|
||||||
"@types/pg": "^8.11.0",
|
"@types/pg": "^8.11.0",
|
||||||
"@types/pngjs": "^6.0.4",
|
"@types/pngjs": "^6.0.4",
|
||||||
"@types/supertest": "^6.0.2",
|
"@types/supertest": "^6.0.2",
|
||||||
@@ -23,8 +23,8 @@
|
|||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-prettier": "^5.1.3",
|
"eslint-plugin-prettier": "^5.1.3",
|
||||||
"eslint-plugin-unicorn": "^53.0.0",
|
"eslint-plugin-unicorn": "^54.0.0",
|
||||||
"exiftool-vendored": "^26.0.0",
|
"exiftool-vendored": "^27.0.0",
|
||||||
"luxon": "^3.4.4",
|
"luxon": "^3.4.4",
|
||||||
"pg": "^8.11.3",
|
"pg": "^8.11.3",
|
||||||
"pngjs": "^7.0.0",
|
"pngjs": "^7.0.0",
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
},
|
},
|
||||||
"../cli": {
|
"../cli": {
|
||||||
"name": "@immich/cli",
|
"name": "@immich/cli",
|
||||||
"version": "2.2.4",
|
"version": "2.2.7",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "GNU Affero General Public License version 3",
|
"license": "GNU Affero General Public License version 3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
"@types/cli-progress": "^3.11.0",
|
"@types/cli-progress": "^3.11.0",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/mock-fs": "^4.13.1",
|
"@types/mock-fs": "^4.13.1",
|
||||||
"@types/node": "^20.3.1",
|
"@types/node": "^20.14.9",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
||||||
"@typescript-eslint/parser": "^7.0.0",
|
"@typescript-eslint/parser": "^7.0.0",
|
||||||
"@vitest/coverage-v8": "^1.2.2",
|
"@vitest/coverage-v8": "^1.2.2",
|
||||||
@@ -65,7 +65,7 @@
|
|||||||
"eslint": "^8.56.0",
|
"eslint": "^8.56.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-prettier": "^5.1.3",
|
"eslint-plugin-prettier": "^5.1.3",
|
||||||
"eslint-plugin-unicorn": "^53.0.0",
|
"eslint-plugin-unicorn": "^54.0.0",
|
||||||
"mock-fs": "^5.2.0",
|
"mock-fs": "^5.2.0",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
"prettier-plugin-organize-imports": "^3.2.4",
|
"prettier-plugin-organize-imports": "^3.2.4",
|
||||||
@@ -81,14 +81,14 @@
|
|||||||
},
|
},
|
||||||
"../open-api/typescript-sdk": {
|
"../open-api/typescript-sdk": {
|
||||||
"name": "@immich/sdk",
|
"name": "@immich/sdk",
|
||||||
"version": "1.106.4",
|
"version": "1.107.2",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "GNU Affero General Public License version 3",
|
"license": "GNU Affero General Public License version 3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@oazapfts/runtime": "^1.0.2"
|
"@oazapfts/runtime": "^1.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^20.11.0",
|
"@types/node": "^20.14.9",
|
||||||
"typescript": "^5.3.3"
|
"typescript": "^5.3.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -971,18 +971,19 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@playwright/test": {
|
"node_modules/@playwright/test": {
|
||||||
"version": "1.44.1",
|
"version": "1.45.0",
|
||||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.44.1.tgz",
|
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.45.0.tgz",
|
||||||
"integrity": "sha512-1hZ4TNvD5z9VuhNJ/walIjvMVvYkZKf71axoF/uiAqpntQJXpG64dlXhoDXE3OczPuTuvjf/M5KWFg5VAVUS3Q==",
|
"integrity": "sha512-TVYsfMlGAaxeUllNkywbwek67Ncf8FRGn8ZlRdO291OL3NjG9oMbfVhyP82HQF0CZLMrYsvesqoUekxdWuF9Qw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"playwright": "1.44.1"
|
"playwright": "1.45.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"playwright": "cli.js"
|
"playwright": "cli.js"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||||
@@ -1230,9 +1231,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "20.12.13",
|
"version": "20.14.9",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.13.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.9.tgz",
|
||||||
"integrity": "sha512-gBGeanV41c1L171rR7wjbMiEpEI/l5XFQdLLfhr/REwpgDy/4U8y89+i8kRiLzDyZdOkXh+cRaTetUnCYutoXA==",
|
"integrity": "sha512-06OCtnTXtWOZBJlRApleWndH4JsRVs1pDCc8dLSQp+7PpUpX3ePdHyeNSFTeSe7FtKyQkrlPvHwJOW3SLd8Oyg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -1344,17 +1345,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "7.11.0",
|
"version": "7.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.14.1.tgz",
|
||||||
"integrity": "sha512-P+qEahbgeHW4JQ/87FuItjBj8O3MYv5gELDzr8QaQ7fsll1gSMTYb6j87MYyxwf3DtD7uGFB9ShwgmCJB5KmaQ==",
|
"integrity": "sha512-aAJd6bIf2vvQRjUG3ZkNXkmBpN+J7Wd0mfQiiVCJMu9Z5GcZZdcc0j8XwN/BM97Fl7e3SkTXODSk4VehUv7CGw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/regexpp": "^4.10.0",
|
"@eslint-community/regexpp": "^4.10.0",
|
||||||
"@typescript-eslint/scope-manager": "7.11.0",
|
"@typescript-eslint/scope-manager": "7.14.1",
|
||||||
"@typescript-eslint/type-utils": "7.11.0",
|
"@typescript-eslint/type-utils": "7.14.1",
|
||||||
"@typescript-eslint/utils": "7.11.0",
|
"@typescript-eslint/utils": "7.14.1",
|
||||||
"@typescript-eslint/visitor-keys": "7.11.0",
|
"@typescript-eslint/visitor-keys": "7.14.1",
|
||||||
"graphemer": "^1.4.0",
|
"graphemer": "^1.4.0",
|
||||||
"ignore": "^5.3.1",
|
"ignore": "^5.3.1",
|
||||||
"natural-compare": "^1.4.0",
|
"natural-compare": "^1.4.0",
|
||||||
@@ -1378,16 +1379,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/parser": {
|
"node_modules/@typescript-eslint/parser": {
|
||||||
"version": "7.11.0",
|
"version": "7.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.14.1.tgz",
|
||||||
"integrity": "sha512-yimw99teuaXVWsBcPO1Ais02kwJ1jmNA1KxE7ng0aT7ndr1pT1wqj0OJnsYVGKKlc4QJai86l/025L6z8CljOg==",
|
"integrity": "sha512-8lKUOebNLcR0D7RvlcloOacTOWzOqemWEWkKSVpMZVF/XVcwjPR+3MD08QzbW9TCGJ+DwIc6zUSGZ9vd8cO1IA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "7.11.0",
|
"@typescript-eslint/scope-manager": "7.14.1",
|
||||||
"@typescript-eslint/types": "7.11.0",
|
"@typescript-eslint/types": "7.14.1",
|
||||||
"@typescript-eslint/typescript-estree": "7.11.0",
|
"@typescript-eslint/typescript-estree": "7.14.1",
|
||||||
"@typescript-eslint/visitor-keys": "7.11.0",
|
"@typescript-eslint/visitor-keys": "7.14.1",
|
||||||
"debug": "^4.3.4"
|
"debug": "^4.3.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1407,14 +1408,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/scope-manager": {
|
"node_modules/@typescript-eslint/scope-manager": {
|
||||||
"version": "7.11.0",
|
"version": "7.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.14.1.tgz",
|
||||||
"integrity": "sha512-27tGdVEiutD4POirLZX4YzT180vevUURJl4wJGmm6TrQoiYwuxTIY98PBp6L2oN+JQxzE0URvYlzJaBHIekXAw==",
|
"integrity": "sha512-gPrFSsoYcsffYXTOZ+hT7fyJr95rdVe4kGVX1ps/dJ+DfmlnjFN/GcMxXcVkeHDKqsq6uAcVaQaIi3cFffmAbA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "7.11.0",
|
"@typescript-eslint/types": "7.14.1",
|
||||||
"@typescript-eslint/visitor-keys": "7.11.0"
|
"@typescript-eslint/visitor-keys": "7.14.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || >=20.0.0"
|
"node": "^18.18.0 || >=20.0.0"
|
||||||
@@ -1425,14 +1426,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/type-utils": {
|
"node_modules/@typescript-eslint/type-utils": {
|
||||||
"version": "7.11.0",
|
"version": "7.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.14.1.tgz",
|
||||||
"integrity": "sha512-WmppUEgYy+y1NTseNMJ6mCFxt03/7jTOy08bcg7bxJJdsM4nuhnchyBbE8vryveaJUf62noH7LodPSo5Z0WUCg==",
|
"integrity": "sha512-/MzmgNd3nnbDbOi3LfasXWWe292+iuo+umJ0bCCMCPc1jLO/z2BQmWUUUXvXLbrQey/JgzdF/OV+I5bzEGwJkQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/typescript-estree": "7.11.0",
|
"@typescript-eslint/typescript-estree": "7.14.1",
|
||||||
"@typescript-eslint/utils": "7.11.0",
|
"@typescript-eslint/utils": "7.14.1",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"ts-api-utils": "^1.3.0"
|
"ts-api-utils": "^1.3.0"
|
||||||
},
|
},
|
||||||
@@ -1453,9 +1454,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/types": {
|
"node_modules/@typescript-eslint/types": {
|
||||||
"version": "7.11.0",
|
"version": "7.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.14.1.tgz",
|
||||||
"integrity": "sha512-MPEsDRZTyCiXkD4vd3zywDCifi7tatc4K37KqTprCvaXptP7Xlpdw0NR2hRJTetG5TxbWDB79Ys4kLmHliEo/w==",
|
"integrity": "sha512-mL7zNEOQybo5R3AavY+Am7KLv8BorIv7HCYS5rKoNZKQD9tsfGUpO4KdAn3sSUvTiS4PQkr2+K0KJbxj8H9NDg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1467,14 +1468,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree": {
|
"node_modules/@typescript-eslint/typescript-estree": {
|
||||||
"version": "7.11.0",
|
"version": "7.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.14.1.tgz",
|
||||||
"integrity": "sha512-cxkhZ2C/iyi3/6U9EPc5y+a6csqHItndvN/CzbNXTNrsC3/ASoYQZEt9uMaEp+xFNjasqQyszp5TumAVKKvJeQ==",
|
"integrity": "sha512-k5d0VuxViE2ulIO6FbxxSZaxqDVUyMbXcidC8rHvii0I56XZPv8cq+EhMns+d/EVIL41sMXqRbK3D10Oza1bbA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "7.11.0",
|
"@typescript-eslint/types": "7.14.1",
|
||||||
"@typescript-eslint/visitor-keys": "7.11.0",
|
"@typescript-eslint/visitor-keys": "7.14.1",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"globby": "^11.1.0",
|
"globby": "^11.1.0",
|
||||||
"is-glob": "^4.0.3",
|
"is-glob": "^4.0.3",
|
||||||
@@ -1506,9 +1507,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
|
"node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
|
||||||
"version": "9.0.4",
|
"version": "9.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
|
||||||
"integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
|
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -1522,16 +1523,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/utils": {
|
"node_modules/@typescript-eslint/utils": {
|
||||||
"version": "7.11.0",
|
"version": "7.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.14.1.tgz",
|
||||||
"integrity": "sha512-xlAWwPleNRHwF37AhrZurOxA1wyXowW4PqVXZVUNCLjB48CqdPJoJWkrpH2nij9Q3Lb7rtWindtoXwxjxlKKCA==",
|
"integrity": "sha512-CMmVVELns3nak3cpJhZosDkm63n+DwBlDX8g0k4QUa9BMnF+lH2lr3d130M1Zt1xxmB3LLk3NV7KQCq86ZBBhQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.4.0",
|
"@eslint-community/eslint-utils": "^4.4.0",
|
||||||
"@typescript-eslint/scope-manager": "7.11.0",
|
"@typescript-eslint/scope-manager": "7.14.1",
|
||||||
"@typescript-eslint/types": "7.11.0",
|
"@typescript-eslint/types": "7.14.1",
|
||||||
"@typescript-eslint/typescript-estree": "7.11.0"
|
"@typescript-eslint/typescript-estree": "7.14.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || >=20.0.0"
|
"node": "^18.18.0 || >=20.0.0"
|
||||||
@@ -1545,13 +1546,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/visitor-keys": {
|
"node_modules/@typescript-eslint/visitor-keys": {
|
||||||
"version": "7.11.0",
|
"version": "7.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.14.1.tgz",
|
||||||
"integrity": "sha512-7syYk4MzjxTEk0g/w3iqtgxnFQspDJfn6QKD36xMuuhTzjcxY7F8EmBLnALjVyaOF1/bVocu3bS/2/F7rXrveQ==",
|
"integrity": "sha512-Crb+F75U1JAEtBeQGxSKwI60hZmmzaqA3z9sYsVm8X7W5cwLEm5bRe0/uXS6+MR/y8CVpKSR/ontIAIEPFcEkA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "7.11.0",
|
"@typescript-eslint/types": "7.14.1",
|
||||||
"eslint-visitor-keys": "^3.4.3"
|
"eslint-visitor-keys": "^3.4.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1671,10 +1672,11 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.11.3",
|
"version": "8.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz",
|
||||||
"integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
|
"integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
},
|
},
|
||||||
@@ -2276,15 +2278,15 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/engine.io-client": {
|
"node_modules/engine.io-client": {
|
||||||
"version": "6.5.3",
|
"version": "6.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.4.tgz",
|
||||||
"integrity": "sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==",
|
"integrity": "sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@socket.io/component-emitter": "~3.1.0",
|
"@socket.io/component-emitter": "~3.1.0",
|
||||||
"debug": "~4.3.1",
|
"debug": "~4.3.1",
|
||||||
"engine.io-parser": "~5.2.1",
|
"engine.io-parser": "~5.2.1",
|
||||||
"ws": "~8.11.0",
|
"ws": "~8.17.1",
|
||||||
"xmlhttprequest-ssl": "~2.0.0"
|
"xmlhttprequest-ssl": "~2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2484,10 +2486,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint-plugin-unicorn": {
|
"node_modules/eslint-plugin-unicorn": {
|
||||||
"version": "53.0.0",
|
"version": "54.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-53.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-54.0.0.tgz",
|
||||||
"integrity": "sha512-kuTcNo9IwwUCfyHGwQFOK/HjJAYzbODHN3wP0PgqbW+jbXqpNWxNVpVhj2tO9SixBwuAdmal8rVcWKBxwFnGuw==",
|
"integrity": "sha512-XxYLRiYtAWiAjPv6z4JREby1TAE2byBC7wlh0V4vWDCpccOSU1KovWV//jqPXF6bq3WKxqX9rdjoRQ1EhdmNdQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-validator-identifier": "^7.24.5",
|
"@babel/helper-validator-identifier": "^7.24.5",
|
||||||
"@eslint-community/eslint-utils": "^4.4.0",
|
"@eslint-community/eslint-utils": "^4.4.0",
|
||||||
@@ -2517,10 +2520,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint-plugin-unicorn/node_modules/@eslint/eslintrc": {
|
"node_modules/eslint-plugin-unicorn/node_modules/@eslint/eslintrc": {
|
||||||
"version": "3.0.2",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz",
|
||||||
"integrity": "sha512-wV19ZEGEMAC1eHgrS7UQPqsdEiCIbTKTasEfcXAigzoXICcqZSjBZEHlZwNVvKg6UBCjSlos84XiLqsRJnIcIg==",
|
"integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ajv": "^6.12.4",
|
"ajv": "^6.12.4",
|
||||||
"debug": "^4.3.2",
|
"debug": "^4.3.2",
|
||||||
@@ -2544,6 +2548,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz",
|
||||||
"integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==",
|
"integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
},
|
},
|
||||||
@@ -2552,12 +2557,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint-plugin-unicorn/node_modules/espree": {
|
"node_modules/eslint-plugin-unicorn/node_modules/espree": {
|
||||||
"version": "10.0.1",
|
"version": "10.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/espree/-/espree-10.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz",
|
||||||
"integrity": "sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==",
|
"integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"acorn": "^8.11.3",
|
"acorn": "^8.12.0",
|
||||||
"acorn-jsx": "^5.3.2",
|
"acorn-jsx": "^5.3.2",
|
||||||
"eslint-visitor-keys": "^4.0.0"
|
"eslint-visitor-keys": "^4.0.0"
|
||||||
},
|
},
|
||||||
@@ -2573,6 +2579,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
|
||||||
"integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
|
"integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
},
|
},
|
||||||
@@ -2700,9 +2707,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/exiftool-vendored": {
|
"node_modules/exiftool-vendored": {
|
||||||
"version": "26.1.0",
|
"version": "27.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/exiftool-vendored/-/exiftool-vendored-26.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/exiftool-vendored/-/exiftool-vendored-27.0.0.tgz",
|
||||||
"integrity": "sha512-Bhy2Ia86Agt3+PbJJhWeVMqJNXl74XJ0Oygef5F5uCL13fTxlmF8dECHiChyx8bBc3sxIw+2Q3ehWunJh3bs6w==",
|
"integrity": "sha512-/jHX8Jjadj0YJzpqnuBo1Yy2ln2hnRbBIc+3jcVOLQ6qhHEKsLRlfJ145Ghn7k/EcnfpDzVX3V8AUCTC8juTow==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -4127,10 +4134,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pg": {
|
"node_modules/pg": {
|
||||||
"version": "8.11.5",
|
"version": "8.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.11.5.tgz",
|
"resolved": "https://registry.npmjs.org/pg/-/pg-8.12.0.tgz",
|
||||||
"integrity": "sha512-jqgNHSKL5cbDjFlHyYsCXmQDrfIX/3RsNwYqpd4N0Kt8niLuNoRNH+aazv6cOd43gPh9Y4DjQCtb+X0MH0Hvnw==",
|
"integrity": "sha512-A+LHUSnwnxrnL/tZ+OLfqR1SxLN3c/pgDztZ47Rpbsd4jUytsTtwQo/TLPRzPJMp/1pbhYVhH9cuSZLAajNfjQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"pg-connection-string": "^2.6.4",
|
"pg-connection-string": "^2.6.4",
|
||||||
"pg-pool": "^3.6.2",
|
"pg-pool": "^3.6.2",
|
||||||
@@ -4255,33 +4263,35 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/playwright": {
|
"node_modules/playwright": {
|
||||||
"version": "1.44.1",
|
"version": "1.45.0",
|
||||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.44.1.tgz",
|
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.45.0.tgz",
|
||||||
"integrity": "sha512-qr/0UJ5CFAtloI3avF95Y0L1xQo6r3LQArLIg/z/PoGJ6xa+EwzrwO5lpNr/09STxdHuUoP2mvuELJS+hLdtgg==",
|
"integrity": "sha512-4z3ac3plDfYzGB6r0Q3LF8POPR20Z8D0aXcxbJvmfMgSSq1hkcgvFRXJk9rUq5H/MJ0Ktal869hhOdI/zUTeLA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"playwright-core": "1.44.1"
|
"playwright-core": "1.45.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"playwright": "cli.js"
|
"playwright": "cli.js"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16"
|
"node": ">=18"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"fsevents": "2.3.2"
|
"fsevents": "2.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/playwright-core": {
|
"node_modules/playwright-core": {
|
||||||
"version": "1.44.1",
|
"version": "1.45.0",
|
||||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.44.1.tgz",
|
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.45.0.tgz",
|
||||||
"integrity": "sha512-wh0JWtYTrhv1+OSsLPgFzGzt67Y7BE/ZS3jEqgGBlp2ppp1ZDj8c+9IARNW4dwf1poq5MgHreEM2KV/GuR4cFA==",
|
"integrity": "sha512-lZmHlFQ0VYSpAs43dRq1/nJ9G/6SiTI7VPqidld9TDefL9tX87bTKExWZZUF5PeRyqtXqd8fQi2qmfIedkwsNQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
"bin": {
|
"bin": {
|
||||||
"playwright-core": "cli.js"
|
"playwright-core": "cli.js"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pluralize": {
|
"node_modules/pluralize": {
|
||||||
@@ -4385,10 +4395,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prettier": {
|
"node_modules/prettier": {
|
||||||
"version": "3.2.5",
|
"version": "3.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz",
|
||||||
"integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==",
|
"integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"prettier": "bin/prettier.cjs"
|
"prettier": "bin/prettier.cjs"
|
||||||
},
|
},
|
||||||
@@ -5260,10 +5271,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript": {
|
"node_modules/typescript": {
|
||||||
"version": "5.4.5",
|
"version": "5.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.2.tgz",
|
||||||
"integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
|
"integrity": "sha512-NcRtPEOsPFFWjobJEtfihkLCZCXZt/os3zf8nTxjVH3RvTSxjrCamJpbExGvYOF+tFHc3pA65qpdwPbzjohhew==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
@@ -5572,16 +5584,16 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/ws": {
|
"node_modules/ws": {
|
||||||
"version": "8.11.0",
|
"version": "8.17.1",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
||||||
"integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
|
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10.0.0"
|
"node": ">=10.0.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"bufferutil": "^4.0.1",
|
"bufferutil": "^4.0.1",
|
||||||
"utf-8-validate": "^5.0.2"
|
"utf-8-validate": ">=5.0.2"
|
||||||
},
|
},
|
||||||
"peerDependenciesMeta": {
|
"peerDependenciesMeta": {
|
||||||
"bufferutil": {
|
"bufferutil": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "immich-e2e",
|
"name": "immich-e2e",
|
||||||
"version": "1.106.4",
|
"version": "1.107.2",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
"@immich/sdk": "file:../open-api/typescript-sdk",
|
"@immich/sdk": "file:../open-api/typescript-sdk",
|
||||||
"@playwright/test": "^1.44.1",
|
"@playwright/test": "^1.44.1",
|
||||||
"@types/luxon": "^3.4.2",
|
"@types/luxon": "^3.4.2",
|
||||||
"@types/node": "^20.11.17",
|
"@types/node": "^20.14.9",
|
||||||
"@types/pg": "^8.11.0",
|
"@types/pg": "^8.11.0",
|
||||||
"@types/pngjs": "^6.0.4",
|
"@types/pngjs": "^6.0.4",
|
||||||
"@types/supertest": "^6.0.2",
|
"@types/supertest": "^6.0.2",
|
||||||
@@ -33,8 +33,8 @@
|
|||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-prettier": "^5.1.3",
|
"eslint-plugin-prettier": "^5.1.3",
|
||||||
"eslint-plugin-unicorn": "^53.0.0",
|
"eslint-plugin-unicorn": "^54.0.0",
|
||||||
"exiftool-vendored": "^26.0.0",
|
"exiftool-vendored": "^27.0.0",
|
||||||
"luxon": "^3.4.4",
|
"luxon": "^3.4.4",
|
||||||
"pg": "^8.11.3",
|
"pg": "^8.11.3",
|
||||||
"pngjs": "^7.0.0",
|
"pngjs": "^7.0.0",
|
||||||
@@ -47,6 +47,6 @@
|
|||||||
"vitest": "^1.3.0"
|
"vitest": "^1.3.0"
|
||||||
},
|
},
|
||||||
"volta": {
|
"volta": {
|
||||||
"node": "20.14.0"
|
"node": "20.15.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ describe('/albums', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await addAssetsToAlbum(
|
await addAssetsToAlbum(
|
||||||
{ id: user2Albums[0].id, bulkIdsDto: { ids: [user1Asset1.id] } },
|
{ id: user2Albums[0].id, bulkIdsDto: { ids: [user1Asset1.id, user1Asset2.id] } },
|
||||||
{ headers: asBearerAuth(user1.accessToken) },
|
{ headers: asBearerAuth(user1.accessToken) },
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -261,7 +261,7 @@ describe('/albums', () => {
|
|||||||
.get(`/albums?assetId=${user1Asset2.id}`)
|
.get(`/albums?assetId=${user1Asset2.id}`)
|
||||||
.set('Authorization', `Bearer ${user1.accessToken}`);
|
.set('Authorization', `Bearer ${user1.accessToken}`);
|
||||||
expect(status).toBe(200);
|
expect(status).toBe(200);
|
||||||
expect(body).toHaveLength(1);
|
expect(body).toHaveLength(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return the album collection filtered by assetId and ignores shared=true', async () => {
|
it('should return the album collection filtered by assetId and ignores shared=true', async () => {
|
||||||
@@ -509,7 +509,17 @@ describe('/albums', () => {
|
|||||||
expect(body).toEqual(errorDto.unauthorized);
|
expect(body).toEqual(errorDto.unauthorized);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not be able to remove foreign asset from own album', async () => {
|
it('should require authorization', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.delete(`/albums/${user1Albums[1].id}/assets`)
|
||||||
|
.set('Authorization', `Bearer ${user2.accessToken}`)
|
||||||
|
.send({ ids: [user1Asset1.id] });
|
||||||
|
|
||||||
|
expect(status).toBe(400);
|
||||||
|
expect(body).toEqual(errorDto.noPermission);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to remove foreign asset from owned album', async () => {
|
||||||
const { status, body } = await request(app)
|
const { status, body } = await request(app)
|
||||||
.delete(`/albums/${user2Albums[0].id}/assets`)
|
.delete(`/albums/${user2Albums[0].id}/assets`)
|
||||||
.set('Authorization', `Bearer ${user2.accessToken}`)
|
.set('Authorization', `Bearer ${user2.accessToken}`)
|
||||||
@@ -519,8 +529,7 @@ describe('/albums', () => {
|
|||||||
expect(body).toEqual([
|
expect(body).toEqual([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: user1Asset1.id,
|
id: user1Asset1.id,
|
||||||
success: false,
|
success: true,
|
||||||
error: 'no_permission',
|
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
@@ -555,10 +564,10 @@ describe('/albums', () => {
|
|||||||
const { status, body } = await request(app)
|
const { status, body } = await request(app)
|
||||||
.delete(`/albums/${user2Albums[0].id}/assets`)
|
.delete(`/albums/${user2Albums[0].id}/assets`)
|
||||||
.set('Authorization', `Bearer ${user1.accessToken}`)
|
.set('Authorization', `Bearer ${user1.accessToken}`)
|
||||||
.send({ ids: [user1Asset1.id] });
|
.send({ ids: [user1Asset2.id] });
|
||||||
|
|
||||||
expect(status).toBe(200);
|
expect(status).toBe(200);
|
||||||
expect(body).toEqual([expect.objectContaining({ id: user1Asset1.id, success: true })]);
|
expect(body).toEqual([expect.objectContaining({ id: user1Asset2.id, success: true })]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not be able to remove assets from album as a viewer', async () => {
|
it('should not be able to remove assets from album as a viewer', async () => {
|
||||||
|
|||||||
@@ -588,6 +588,58 @@ describe('/asset', () => {
|
|||||||
const after = await utils.getAssetInfo(admin.accessToken, assetId);
|
const after = await utils.getAssetInfo(admin.accessToken, assetId);
|
||||||
expect(after.isTrashed).toBe(true);
|
expect(after.isTrashed).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should clean up live photos', async () => {
|
||||||
|
const { id: motionId } = await utils.createAsset(admin.accessToken, {
|
||||||
|
assetData: { filename: 'test.mp4', bytes: makeRandomImage() },
|
||||||
|
});
|
||||||
|
const { id: photoId } = await utils.createAsset(admin.accessToken, { livePhotoVideoId: motionId });
|
||||||
|
|
||||||
|
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: photoId });
|
||||||
|
await utils.waitForWebsocketEvent({ event: 'assetHidden', id: motionId });
|
||||||
|
|
||||||
|
const asset = await utils.getAssetInfo(admin.accessToken, photoId);
|
||||||
|
expect(asset.livePhotoVideoId).toBe(motionId);
|
||||||
|
|
||||||
|
const { status } = await request(app)
|
||||||
|
.delete('/assets')
|
||||||
|
.send({ ids: [photoId], force: true })
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
expect(status).toBe(204);
|
||||||
|
|
||||||
|
await utils.waitForWebsocketEvent({ event: 'assetDelete', id: photoId });
|
||||||
|
await utils.waitForWebsocketEvent({ event: 'assetDelete', id: motionId });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not delete a shared motion asset', async () => {
|
||||||
|
const { id: motionId } = await utils.createAsset(admin.accessToken, {
|
||||||
|
assetData: { filename: 'test.mp4', bytes: makeRandomImage() },
|
||||||
|
});
|
||||||
|
const { id: asset1 } = await utils.createAsset(admin.accessToken, { livePhotoVideoId: motionId });
|
||||||
|
const { id: asset2 } = await utils.createAsset(admin.accessToken, { livePhotoVideoId: motionId });
|
||||||
|
|
||||||
|
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: asset1 });
|
||||||
|
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: asset2 });
|
||||||
|
await utils.waitForWebsocketEvent({ event: 'assetHidden', id: motionId });
|
||||||
|
|
||||||
|
const asset = await utils.getAssetInfo(admin.accessToken, asset1);
|
||||||
|
expect(asset.livePhotoVideoId).toBe(motionId);
|
||||||
|
|
||||||
|
const { status } = await request(app)
|
||||||
|
.delete('/assets')
|
||||||
|
.send({ ids: [asset1], force: true })
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
expect(status).toBe(204);
|
||||||
|
|
||||||
|
await utils.waitForWebsocketEvent({ event: 'assetDelete', id: asset1 });
|
||||||
|
await utils.waitForQueueFinish(admin.accessToken, 'backgroundTask');
|
||||||
|
|
||||||
|
await expect(utils.getAssetInfo(admin.accessToken, motionId)).resolves.toMatchObject({ id: motionId });
|
||||||
|
await expect(utils.getAssetInfo(admin.accessToken, asset2)).resolves.toMatchObject({
|
||||||
|
id: asset2,
|
||||||
|
livePhotoVideoId: motionId,
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('GET /assets/:id/thumbnail', () => {
|
describe('GET /assets/:id/thumbnail', () => {
|
||||||
|
|||||||
@@ -230,4 +230,21 @@ describe('/people', () => {
|
|||||||
expect(body).toMatchObject({ birthDate: null });
|
expect(body).toMatchObject({ birthDate: null });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('POST /people/:id/merge', () => {
|
||||||
|
it('should require authentication', async () => {
|
||||||
|
const { status, body } = await request(app).post(`/people/${uuidDto.notFound}/merge`);
|
||||||
|
expect(status).toBe(401);
|
||||||
|
expect(body).toEqual(errorDto.unauthorized);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not supporting merging a person into themselves', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.post(`/people/${visiblePerson.id}/merge`)
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`)
|
||||||
|
.send({ ids: [visiblePerson.id] });
|
||||||
|
expect(status).toBe(400);
|
||||||
|
expect(body).toEqual(errorDto.badRequest('Cannot merge a person into themselves'));
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -339,6 +339,13 @@ describe('/search', () => {
|
|||||||
should: 'should search by model',
|
should: 'should search by model',
|
||||||
deferred: () => ({ dto: { model: 'Canon EOS 7D' }, assets: [assetDenali] }),
|
deferred: () => ({ dto: { model: 'Canon EOS 7D' }, assets: [assetDenali] }),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
should: 'should allow searching the upload library (libraryId: null)',
|
||||||
|
deferred: () => ({
|
||||||
|
dto: { libraryId: null, size: 1 },
|
||||||
|
assets: [assetLast],
|
||||||
|
}),
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const { should, deferred } of searchTests) {
|
for (const { should, deferred } of searchTests) {
|
||||||
|
|||||||
@@ -15,6 +15,40 @@ describe('/server-info', () => {
|
|||||||
nonAdmin = await utils.userSetup(admin.accessToken, createUserDto.user1);
|
nonAdmin = await utils.userSetup(admin.accessToken, createUserDto.user1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('GET /server-info/about', () => {
|
||||||
|
it('should require authentication', async () => {
|
||||||
|
const { status, body } = await request(app).get('/server-info/about');
|
||||||
|
expect(status).toBe(401);
|
||||||
|
expect(body).toEqual(errorDto.unauthorized);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return about information', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.get('/server-info/about')
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toEqual({
|
||||||
|
version: expect.any(String),
|
||||||
|
versionUrl: expect.any(String),
|
||||||
|
repository: 'immich-app/immich',
|
||||||
|
repositoryUrl: 'https://github.com/immich-app/immich',
|
||||||
|
build: '1234567890',
|
||||||
|
buildUrl: 'https://github.com/immich-app/immich/actions/runs/1234567890',
|
||||||
|
buildImage: 'e2e',
|
||||||
|
buildImageUrl: 'https://github.com/immich-app/immich/pkgs/container/immich-server',
|
||||||
|
sourceRef: 'e2e',
|
||||||
|
sourceCommit: 'e2eeeeeeeeeeeeeeeeee',
|
||||||
|
sourceUrl: 'https://github.com/immich-app/immich/commit/e2eeeeeeeeeeeeeeeeee',
|
||||||
|
nodejs: expect.any(String),
|
||||||
|
ffmpeg: expect.any(String),
|
||||||
|
imagemagick: expect.any(String),
|
||||||
|
libvips: expect.any(String),
|
||||||
|
exiftool: expect.any(String),
|
||||||
|
licensed: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('GET /server-info/storage', () => {
|
describe('GET /server-info/storage', () => {
|
||||||
it('should require authentication', async () => {
|
it('should require authentication', async () => {
|
||||||
const { status, body } = await request(app).get('/server-info/storage');
|
const { status, body } = await request(app).get('/server-info/storage');
|
||||||
|
|||||||
307
e2e/src/api/specs/server.e2e-spec.ts
Normal file
307
e2e/src/api/specs/server.e2e-spec.ts
Normal file
@@ -0,0 +1,307 @@
|
|||||||
|
import { LoginResponseDto } from '@immich/sdk';
|
||||||
|
import { createUserDto } from 'src/fixtures';
|
||||||
|
import { errorDto } from 'src/responses';
|
||||||
|
import { app, utils } from 'src/utils';
|
||||||
|
import request from 'supertest';
|
||||||
|
import { beforeAll, describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
|
const serverLicense = {
|
||||||
|
licenseKey: 'IMSV-6ECZ-91TE-WZRM-Q7AQ-MBN4-UW48-2CPT-71X9',
|
||||||
|
activationKey:
|
||||||
|
'4kJUNUWMq13J14zqPFm1NodRcI6MV6DeOGvQNIgrM8Sc9nv669wyEVvFw1Nz4Kb1W7zLWblOtXEQzpRRqC4r4fKjewJxfbpeo9sEsqAVIfl4Ero-Vp1Dg21-sVdDGZEAy2oeTCXAyCT5d1JqrqR6N1qTAm4xOx9ujXQRFYhjRG8uwudw7_Q49pF18Tj5OEv9qCqElxztoNck4i6O_azsmsoOQrLIENIWPh3EynBN3ESpYERdCgXO8MlWeuG14_V1HbNjnJPZDuvYg__YfMzoOEtfm1sCqEaJ2Ww-BaX7yGfuCL4XsuZlCQQNHjfscy_WywVfIZPKCiW8QR74i0cSzQ',
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('/server', () => {
|
||||||
|
let admin: LoginResponseDto;
|
||||||
|
let nonAdmin: LoginResponseDto;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
await utils.resetDatabase();
|
||||||
|
admin = await utils.adminSetup({ onboarding: false });
|
||||||
|
nonAdmin = await utils.userSetup(admin.accessToken, createUserDto.user1);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('GET /server/about', () => {
|
||||||
|
it('should require authentication', async () => {
|
||||||
|
const { status, body } = await request(app).get('/server/about');
|
||||||
|
expect(status).toBe(401);
|
||||||
|
expect(body).toEqual(errorDto.unauthorized);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return about information', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.get('/server/about')
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toEqual({
|
||||||
|
version: expect.any(String),
|
||||||
|
versionUrl: expect.any(String),
|
||||||
|
repository: 'immich-app/immich',
|
||||||
|
repositoryUrl: 'https://github.com/immich-app/immich',
|
||||||
|
build: '1234567890',
|
||||||
|
buildUrl: 'https://github.com/immich-app/immich/actions/runs/1234567890',
|
||||||
|
buildImage: 'e2e',
|
||||||
|
buildImageUrl: 'https://github.com/immich-app/immich/pkgs/container/immich-server',
|
||||||
|
sourceRef: 'e2e',
|
||||||
|
sourceCommit: 'e2eeeeeeeeeeeeeeeeee',
|
||||||
|
sourceUrl: 'https://github.com/immich-app/immich/commit/e2eeeeeeeeeeeeeeeeee',
|
||||||
|
nodejs: expect.any(String),
|
||||||
|
ffmpeg: expect.any(String),
|
||||||
|
imagemagick: expect.any(String),
|
||||||
|
libvips: expect.any(String),
|
||||||
|
exiftool: expect.any(String),
|
||||||
|
licensed: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('GET /server/storage', () => {
|
||||||
|
it('should require authentication', async () => {
|
||||||
|
const { status, body } = await request(app).get('/server/storage');
|
||||||
|
expect(status).toBe(401);
|
||||||
|
expect(body).toEqual(errorDto.unauthorized);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the disk information', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.get('/server/storage')
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toEqual({
|
||||||
|
diskAvailable: expect.any(String),
|
||||||
|
diskAvailableRaw: expect.any(Number),
|
||||||
|
diskSize: expect.any(String),
|
||||||
|
diskSizeRaw: expect.any(Number),
|
||||||
|
diskUsagePercentage: expect.any(Number),
|
||||||
|
diskUse: expect.any(String),
|
||||||
|
diskUseRaw: expect.any(Number),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('GET /server/ping', () => {
|
||||||
|
it('should respond with pong', async () => {
|
||||||
|
const { status, body } = await request(app).get('/server/ping');
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toEqual({ res: 'pong' });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('GET /server/version', () => {
|
||||||
|
it('should respond with the server version', async () => {
|
||||||
|
const { status, body } = await request(app).get('/server/version');
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toEqual({
|
||||||
|
major: expect.any(Number),
|
||||||
|
minor: expect.any(Number),
|
||||||
|
patch: expect.any(Number),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('GET /server/features', () => {
|
||||||
|
it('should respond with the server features', async () => {
|
||||||
|
const { status, body } = await request(app).get('/server/features');
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toEqual({
|
||||||
|
smartSearch: false,
|
||||||
|
configFile: false,
|
||||||
|
duplicateDetection: false,
|
||||||
|
facialRecognition: false,
|
||||||
|
map: true,
|
||||||
|
reverseGeocoding: true,
|
||||||
|
oauth: false,
|
||||||
|
oauthAutoLaunch: false,
|
||||||
|
passwordLogin: true,
|
||||||
|
search: true,
|
||||||
|
sidecar: true,
|
||||||
|
trash: true,
|
||||||
|
email: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('GET /server/config', () => {
|
||||||
|
it('should respond with the server configuration', async () => {
|
||||||
|
const { status, body } = await request(app).get('/server/config');
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toEqual({
|
||||||
|
loginPageMessage: '',
|
||||||
|
oauthButtonText: 'Login with OAuth',
|
||||||
|
trashDays: 30,
|
||||||
|
userDeleteDelay: 7,
|
||||||
|
isInitialized: true,
|
||||||
|
externalDomain: '',
|
||||||
|
isOnboarded: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('GET /server/statistics', () => {
|
||||||
|
it('should require authentication', async () => {
|
||||||
|
const { status, body } = await request(app).get('/server/statistics');
|
||||||
|
expect(status).toBe(401);
|
||||||
|
expect(body).toEqual(errorDto.unauthorized);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should only work for admins', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.get('/server/statistics')
|
||||||
|
.set('Authorization', `Bearer ${nonAdmin.accessToken}`);
|
||||||
|
expect(status).toBe(403);
|
||||||
|
expect(body).toEqual(errorDto.forbidden);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the server stats', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.get('/server/statistics')
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toEqual({
|
||||||
|
photos: 0,
|
||||||
|
usage: 0,
|
||||||
|
usageByUser: [
|
||||||
|
{
|
||||||
|
quotaSizeInBytes: null,
|
||||||
|
photos: 0,
|
||||||
|
usage: 0,
|
||||||
|
userName: 'Immich Admin',
|
||||||
|
userId: admin.userId,
|
||||||
|
videos: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
quotaSizeInBytes: null,
|
||||||
|
photos: 0,
|
||||||
|
usage: 0,
|
||||||
|
userName: 'User 1',
|
||||||
|
userId: nonAdmin.userId,
|
||||||
|
videos: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
videos: 0,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('GET /server/media-types', () => {
|
||||||
|
it('should return accepted media types', async () => {
|
||||||
|
const { status, body } = await request(app).get('/server/media-types');
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toEqual({
|
||||||
|
sidecar: ['.xmp'],
|
||||||
|
image: expect.any(Array),
|
||||||
|
video: expect.any(Array),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('GET /server/theme', () => {
|
||||||
|
it('should respond with the server theme', async () => {
|
||||||
|
const { status, body } = await request(app).get('/server/theme');
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toEqual({
|
||||||
|
customCss: '',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('GET /server/license', () => {
|
||||||
|
it('should require authentication', async () => {
|
||||||
|
const { status, body } = await request(app).get('/server/license');
|
||||||
|
expect(status).toBe(401);
|
||||||
|
expect(body).toEqual(errorDto.unauthorized);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should only work for admins', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.get('/server/license')
|
||||||
|
.set('Authorization', `Bearer ${nonAdmin.accessToken}`);
|
||||||
|
expect(status).toBe(403);
|
||||||
|
expect(body).toEqual(errorDto.forbidden);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the server license', async () => {
|
||||||
|
await request(app).put('/server/license').set('Authorization', `Bearer ${admin.accessToken}`).send(serverLicense);
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.get('/server/license')
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toEqual({
|
||||||
|
...serverLicense,
|
||||||
|
activatedAt: expect.any(String),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('DELETE /server/license', () => {
|
||||||
|
it('should require authentication', async () => {
|
||||||
|
const { status, body } = await request(app).delete('/server/license');
|
||||||
|
expect(status).toBe(401);
|
||||||
|
expect(body).toEqual(errorDto.unauthorized);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should only work for admins', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.delete('/server/license')
|
||||||
|
.set('Authorization', `Bearer ${nonAdmin.accessToken}`);
|
||||||
|
expect(status).toBe(403);
|
||||||
|
expect(body).toEqual(errorDto.forbidden);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delete the server license', async () => {
|
||||||
|
await request(app)
|
||||||
|
.delete('/server/license')
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`)
|
||||||
|
.send(serverLicense);
|
||||||
|
const { status } = await request(app).get('/server/license').set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
expect(status).toBe(200);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('PUT /server/license', () => {
|
||||||
|
it('should require authentication', async () => {
|
||||||
|
const { status, body } = await request(app).put('/server/license');
|
||||||
|
expect(status).toBe(401);
|
||||||
|
expect(body).toEqual(errorDto.unauthorized);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should only work for admins', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.put('/server/license')
|
||||||
|
.set('Authorization', `Bearer ${nonAdmin.accessToken}`);
|
||||||
|
expect(status).toBe(403);
|
||||||
|
expect(body).toEqual(errorDto.forbidden);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set the server license', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.put('/server/license')
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`)
|
||||||
|
.send(serverLicense);
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toEqual({ ...serverLicense, activatedAt: expect.any(String) });
|
||||||
|
const { body: licenseBody } = await request(app)
|
||||||
|
.get('/server/license')
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
expect(licenseBody).toEqual({ ...serverLicense, activatedAt: expect.any(String) });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reject license not starting with IMSV-', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.put('/server/license')
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`)
|
||||||
|
.send({ licenseKey: 'IMCL-ABCD-ABCD-ABCD-ABCD-ABCD-ABCD-ABCD-ABCD', activationKey: 'activationKey' });
|
||||||
|
expect(status).toBe(400);
|
||||||
|
expect(body.message).toBe('Invalid license key');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reject license with invalid activation key', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.put('/server/license')
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`)
|
||||||
|
.send({ licenseKey: serverLicense.licenseKey, activationKey: `invalid${serverLicense.activationKey}` });
|
||||||
|
expect(status).toBe(400);
|
||||||
|
expect(body.message).toBe('Invalid license key');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
getUserAdmin,
|
getUserAdmin,
|
||||||
getUserPreferencesAdmin,
|
getUserPreferencesAdmin,
|
||||||
login,
|
login,
|
||||||
|
updateAssets,
|
||||||
} from '@immich/sdk';
|
} from '@immich/sdk';
|
||||||
import { Socket } from 'socket.io-client';
|
import { Socket } from 'socket.io-client';
|
||||||
import { createUserDto, uuidDto } from 'src/fixtures';
|
import { createUserDto, uuidDto } from 'src/fixtures';
|
||||||
@@ -20,18 +21,16 @@ describe('/admin/users', () => {
|
|||||||
let nonAdmin: LoginResponseDto;
|
let nonAdmin: LoginResponseDto;
|
||||||
let deletedUser: LoginResponseDto;
|
let deletedUser: LoginResponseDto;
|
||||||
let userToDelete: LoginResponseDto;
|
let userToDelete: LoginResponseDto;
|
||||||
let userToHardDelete: LoginResponseDto;
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await utils.resetDatabase();
|
await utils.resetDatabase();
|
||||||
admin = await utils.adminSetup({ onboarding: false });
|
admin = await utils.adminSetup({ onboarding: false });
|
||||||
|
|
||||||
[websocket, nonAdmin, deletedUser, userToDelete, userToHardDelete] = await Promise.all([
|
[websocket, nonAdmin, deletedUser, userToDelete] = await Promise.all([
|
||||||
utils.connectWebsocket(admin.accessToken),
|
utils.connectWebsocket(admin.accessToken),
|
||||||
utils.userSetup(admin.accessToken, createUserDto.user1),
|
utils.userSetup(admin.accessToken, createUserDto.user1),
|
||||||
utils.userSetup(admin.accessToken, createUserDto.user2),
|
utils.userSetup(admin.accessToken, createUserDto.user2),
|
||||||
utils.userSetup(admin.accessToken, createUserDto.user3),
|
utils.userSetup(admin.accessToken, createUserDto.user3),
|
||||||
utils.userSetup(admin.accessToken, createUserDto.user4),
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
await deleteUserAdmin(
|
await deleteUserAdmin(
|
||||||
@@ -64,13 +63,12 @@ describe('/admin/users', () => {
|
|||||||
.get(`/admin/users`)
|
.get(`/admin/users`)
|
||||||
.set('Authorization', `Bearer ${admin.accessToken}`);
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
expect(status).toBe(200);
|
expect(status).toBe(200);
|
||||||
expect(body).toHaveLength(4);
|
expect(body).toHaveLength(3);
|
||||||
expect(body).toEqual(
|
expect(body).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
expect.objectContaining({ email: admin.userEmail }),
|
expect.objectContaining({ email: admin.userEmail }),
|
||||||
expect.objectContaining({ email: nonAdmin.userEmail }),
|
expect.objectContaining({ email: nonAdmin.userEmail }),
|
||||||
expect.objectContaining({ email: userToDelete.userEmail }),
|
expect.objectContaining({ email: userToDelete.userEmail }),
|
||||||
expect.objectContaining({ email: userToHardDelete.userEmail }),
|
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -81,13 +79,12 @@ describe('/admin/users', () => {
|
|||||||
.set('Authorization', `Bearer ${admin.accessToken}`);
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
|
||||||
expect(status).toBe(200);
|
expect(status).toBe(200);
|
||||||
expect(body).toHaveLength(5);
|
expect(body).toHaveLength(4);
|
||||||
expect(body).toEqual(
|
expect(body).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
expect.objectContaining({ email: admin.userEmail }),
|
expect.objectContaining({ email: admin.userEmail }),
|
||||||
expect.objectContaining({ email: nonAdmin.userEmail }),
|
expect.objectContaining({ email: nonAdmin.userEmail }),
|
||||||
expect.objectContaining({ email: userToDelete.userEmail }),
|
expect.objectContaining({ email: userToDelete.userEmail }),
|
||||||
expect.objectContaining({ email: userToHardDelete.userEmail }),
|
|
||||||
expect.objectContaining({ email: deletedUser.userEmail }),
|
expect.objectContaining({ email: deletedUser.userEmail }),
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
@@ -250,18 +247,23 @@ describe('/admin/users', () => {
|
|||||||
.set('Authorization', `Bearer ${admin.accessToken}`);
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
|
||||||
expect(status).toBe(200);
|
expect(status).toBe(200);
|
||||||
expect(body).toEqual({
|
expect(body).toMatchObject({ avatar: { color: 'orange' } });
|
||||||
avatar: { color: 'orange' },
|
|
||||||
memories: { enabled: false },
|
|
||||||
emailNotifications: { enabled: true, albumInvite: true, albumUpdate: true },
|
|
||||||
});
|
|
||||||
|
|
||||||
const after = await getUserPreferencesAdmin({ id: admin.userId }, { headers: asBearerAuth(admin.accessToken) });
|
const after = await getUserPreferencesAdmin({ id: admin.userId }, { headers: asBearerAuth(admin.accessToken) });
|
||||||
expect(after).toEqual({
|
expect(after).toMatchObject({ avatar: { color: 'orange' } });
|
||||||
avatar: { color: 'orange' },
|
});
|
||||||
memories: { enabled: false },
|
|
||||||
emailNotifications: { enabled: true, albumInvite: true, albumUpdate: true },
|
it('should update download archive size', async () => {
|
||||||
});
|
const { status, body } = await request(app)
|
||||||
|
.put(`/admin/users/${admin.userId}/preferences`)
|
||||||
|
.send({ download: { archiveSize: 1_234_567 } })
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toMatchObject({ download: { archiveSize: 1_234_567 } });
|
||||||
|
|
||||||
|
const after = await getUserPreferencesAdmin({ id: admin.userId }, { headers: asBearerAuth(admin.accessToken) });
|
||||||
|
expect(after).toMatchObject({ download: { archiveSize: 1_234_567 } });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -294,19 +296,49 @@ describe('/admin/users', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should hard delete a user', async () => {
|
it('should hard delete a user', async () => {
|
||||||
|
const user = await utils.userSetup(admin.accessToken, createUserDto.create('hard-delete-1'));
|
||||||
|
|
||||||
const { status, body } = await request(app)
|
const { status, body } = await request(app)
|
||||||
.delete(`/admin/users/${userToHardDelete.userId}`)
|
.delete(`/admin/users/${user.userId}`)
|
||||||
.send({ force: true })
|
.send({ force: true })
|
||||||
.set('Authorization', `Bearer ${admin.accessToken}`);
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
|
||||||
expect(status).toBe(200);
|
expect(status).toBe(200);
|
||||||
expect(body).toMatchObject({
|
expect(body).toMatchObject({
|
||||||
id: userToHardDelete.userId,
|
id: user.userId,
|
||||||
updatedAt: expect.any(String),
|
updatedAt: expect.any(String),
|
||||||
deletedAt: expect.any(String),
|
deletedAt: expect.any(String),
|
||||||
});
|
});
|
||||||
|
|
||||||
await utils.waitForWebsocketEvent({ event: 'userDelete', id: userToHardDelete.userId, timeout: 5000 });
|
await utils.waitForWebsocketEvent({ event: 'userDelete', id: user.userId, timeout: 5000 });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should hard delete a user with stacked assets', async () => {
|
||||||
|
const user = await utils.userSetup(admin.accessToken, createUserDto.create('hard-delete-1'));
|
||||||
|
|
||||||
|
const [asset1, asset2] = await Promise.all([
|
||||||
|
utils.createAsset(user.accessToken),
|
||||||
|
utils.createAsset(user.accessToken),
|
||||||
|
]);
|
||||||
|
|
||||||
|
await updateAssets(
|
||||||
|
{ assetBulkUpdateDto: { stackParentId: asset1.id, ids: [asset2.id] } },
|
||||||
|
{ headers: asBearerAuth(user.accessToken) },
|
||||||
|
);
|
||||||
|
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.delete(`/admin/users/${user.userId}`)
|
||||||
|
.send({ force: true })
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toMatchObject({
|
||||||
|
id: user.userId,
|
||||||
|
updatedAt: expect.any(String),
|
||||||
|
deletedAt: expect.any(String),
|
||||||
|
});
|
||||||
|
|
||||||
|
await utils.waitForWebsocketEvent({ event: 'userDelete', id: user.userId, timeout: 5000 });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,12 @@ import { app, asBearerAuth, utils } from 'src/utils';
|
|||||||
import request from 'supertest';
|
import request from 'supertest';
|
||||||
import { beforeAll, describe, expect, it } from 'vitest';
|
import { beforeAll, describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
|
const userLicense = {
|
||||||
|
licenseKey: 'IMCL-FF69-TUK1-RWZU-V9Q8-QGQS-S5GC-X4R2-UFK4',
|
||||||
|
activationKey:
|
||||||
|
'KuX8KsktrBSiXpQMAH0zLgA5SpijXVr_PDkzLdWUlAogCTMBZ0I3KCHXK0eE9EEd7harxup8_EHMeqAWeHo5VQzol6LGECpFv585U9asXD4Zc-UXt3mhJr2uhazqipBIBwJA2YhmUCDy8hiyiGsukDQNu9Rg9C77UeoKuZBWVjWUBWG0mc1iRqfvF0faVM20w53czAzlhaMxzVGc3Oimbd7xi_CAMSujF_2y8QpA3X2fOVkQkzdcH9lV0COejl7IyH27zQQ9HrlrXv3Lai5Hw67kNkaSjmunVBxC5PS0TpKoc9SfBJMaAGWnaDbjhjYUrm-8nIDQnoeEAidDXVAdPw',
|
||||||
|
};
|
||||||
|
|
||||||
describe('/users', () => {
|
describe('/users', () => {
|
||||||
let admin: LoginResponseDto;
|
let admin: LoginResponseDto;
|
||||||
let deletedUser: LoginResponseDto;
|
let deletedUser: LoginResponseDto;
|
||||||
@@ -72,6 +78,24 @@ describe('/users', () => {
|
|||||||
quotaUsageInBytes: 0,
|
quotaUsageInBytes: 0,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should get my user with license info', async () => {
|
||||||
|
const { status: licenseStatus } = await request(app)
|
||||||
|
.put(`/users/me/license`)
|
||||||
|
.send(userLicense)
|
||||||
|
.set('Authorization', `Bearer ${nonAdmin.accessToken}`);
|
||||||
|
expect(licenseStatus).toBe(200);
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.get(`/users/me`)
|
||||||
|
.set('Authorization', `Bearer ${nonAdmin.accessToken}`);
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toMatchObject({
|
||||||
|
id: nonAdmin.userId,
|
||||||
|
email: nonAdmin.userEmail,
|
||||||
|
quotaUsageInBytes: 0,
|
||||||
|
license: userLicense,
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('PUT /users/me', () => {
|
describe('PUT /users/me', () => {
|
||||||
@@ -173,6 +197,45 @@ describe('/users', () => {
|
|||||||
const after = await getMyPreferences({ headers: asBearerAuth(admin.accessToken) });
|
const after = await getMyPreferences({ headers: asBearerAuth(admin.accessToken) });
|
||||||
expect(after).toMatchObject({ memories: { enabled: false } });
|
expect(after).toMatchObject({ memories: { enabled: false } });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should update avatar color', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.put(`/users/me/preferences`)
|
||||||
|
.send({ avatar: { color: 'blue' } })
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toMatchObject({ avatar: { color: 'blue' } });
|
||||||
|
|
||||||
|
const after = await getMyPreferences({ headers: asBearerAuth(admin.accessToken) });
|
||||||
|
expect(after).toMatchObject({ avatar: { color: 'blue' } });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should require an integer for download archive size', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.put(`/users/me/preferences`)
|
||||||
|
.send({ download: { archiveSize: 1_234_567.89 } })
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
|
||||||
|
expect(status).toBe(400);
|
||||||
|
expect(body).toEqual(errorDto.badRequest(['download.archiveSize must be an integer number']));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update download archive size', async () => {
|
||||||
|
const before = await getMyPreferences({ headers: asBearerAuth(admin.accessToken) });
|
||||||
|
expect(before).toMatchObject({ download: { archiveSize: 4 * 2 ** 30 } });
|
||||||
|
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.put(`/users/me/preferences`)
|
||||||
|
.send({ download: { archiveSize: 1_234_567 } })
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toMatchObject({ download: { archiveSize: 1_234_567 } });
|
||||||
|
|
||||||
|
const after = await getMyPreferences({ headers: asBearerAuth(admin.accessToken) });
|
||||||
|
expect(after).toMatchObject({ download: { archiveSize: 1_234_567 } });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('GET /users/:id', () => {
|
describe('GET /users/:id', () => {
|
||||||
@@ -197,4 +260,81 @@ describe('/users', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('GET /server/license', () => {
|
||||||
|
it('should require authentication', async () => {
|
||||||
|
const { status, body } = await request(app).get('/users/me/license');
|
||||||
|
expect(status).toBe(401);
|
||||||
|
expect(body).toEqual(errorDto.unauthorized);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the user license', async () => {
|
||||||
|
await request(app)
|
||||||
|
.put('/users/me/license')
|
||||||
|
.set('Authorization', `Bearer ${nonAdmin.accessToken}`)
|
||||||
|
.send(userLicense);
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.get('/users/me/license')
|
||||||
|
.set('Authorization', `Bearer ${nonAdmin.accessToken}`);
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toEqual({
|
||||||
|
...userLicense,
|
||||||
|
activatedAt: expect.any(String),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('PUT /users/me/license', () => {
|
||||||
|
it('should require authentication', async () => {
|
||||||
|
const { status } = await request(app).put(`/users/me/license`);
|
||||||
|
expect(status).toEqual(401);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set the user license', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.put(`/users/me/license`)
|
||||||
|
.send(userLicense)
|
||||||
|
.set('Authorization', `Bearer ${nonAdmin.accessToken}`);
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toMatchObject({ ...userLicense, activatedAt: expect.any(String) });
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toEqual({ ...userLicense, activatedAt: expect.any(String) });
|
||||||
|
const { body: licenseBody } = await request(app)
|
||||||
|
.get('/users/me/license')
|
||||||
|
.set('Authorization', `Bearer ${nonAdmin.accessToken}`);
|
||||||
|
expect(licenseBody).toEqual({ ...userLicense, activatedAt: expect.any(String) });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reject license not starting with IMCL-', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.put('/users/me/license')
|
||||||
|
.set('Authorization', `Bearer ${nonAdmin.accessToken}`)
|
||||||
|
.send({ licenseKey: 'IMSV-ABCD-ABCD-ABCD-ABCD-ABCD-ABCD-ABCD-ABCD', activationKey: 'activationKey' });
|
||||||
|
expect(status).toBe(400);
|
||||||
|
expect(body.message).toBe('Invalid license key');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reject license with invalid activation key', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.put('/users/me/license')
|
||||||
|
.set('Authorization', `Bearer ${nonAdmin.accessToken}`)
|
||||||
|
.send({ licenseKey: userLicense.licenseKey, activationKey: `invalid${userLicense.activationKey}` });
|
||||||
|
expect(status).toBe(400);
|
||||||
|
expect(body.message).toBe('Invalid license key');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('DELETE /users/me/license', () => {
|
||||||
|
it('should require authentication', async () => {
|
||||||
|
const { status } = await request(app).put(`/users/me/license`);
|
||||||
|
expect(status).toEqual(401);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delete the user license', async () => {
|
||||||
|
const { status } = await request(app)
|
||||||
|
.delete(`/users/me/license`)
|
||||||
|
.set('Authorization', `Bearer ${nonAdmin.accessToken}`);
|
||||||
|
expect(status).toBe(200);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ export const signupResponseDto = {
|
|||||||
quotaUsageInBytes: 0,
|
quotaUsageInBytes: 0,
|
||||||
quotaSizeInBytes: null,
|
quotaSizeInBytes: null,
|
||||||
status: 'active',
|
status: 'active',
|
||||||
|
license: null,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ import { makeRandomImage } from 'src/generators';
|
|||||||
import request from 'supertest';
|
import request from 'supertest';
|
||||||
|
|
||||||
type CommandResponse = { stdout: string; stderr: string; exitCode: number | null };
|
type CommandResponse = { stdout: string; stderr: string; exitCode: number | null };
|
||||||
type EventType = 'assetUpload' | 'assetUpdate' | 'assetDelete' | 'userDelete';
|
type EventType = 'assetUpload' | 'assetUpdate' | 'assetDelete' | 'userDelete' | 'assetHidden';
|
||||||
type WaitOptions = { event: EventType; id?: string; total?: number; timeout?: number };
|
type WaitOptions = { event: EventType; id?: string; total?: number; timeout?: number };
|
||||||
type AdminSetupOptions = { onboarding?: boolean };
|
type AdminSetupOptions = { onboarding?: boolean };
|
||||||
type AssetData = { bytes?: Buffer; filename: string };
|
type AssetData = { bytes?: Buffer; filename: string };
|
||||||
@@ -92,6 +92,7 @@ const executeCommand = (command: string, args: string[]) => {
|
|||||||
let client: pg.Client | null = null;
|
let client: pg.Client | null = null;
|
||||||
|
|
||||||
const events: Record<EventType, Set<string>> = {
|
const events: Record<EventType, Set<string>> = {
|
||||||
|
assetHidden: new Set<string>(),
|
||||||
assetUpload: new Set<string>(),
|
assetUpload: new Set<string>(),
|
||||||
assetUpdate: new Set<string>(),
|
assetUpdate: new Set<string>(),
|
||||||
assetDelete: new Set<string>(),
|
assetDelete: new Set<string>(),
|
||||||
@@ -203,6 +204,7 @@ export const utils = {
|
|||||||
.on('connect', () => resolve(websocket))
|
.on('connect', () => resolve(websocket))
|
||||||
.on('on_upload_success', (data: AssetResponseDto) => onEvent({ event: 'assetUpload', id: data.id }))
|
.on('on_upload_success', (data: AssetResponseDto) => onEvent({ event: 'assetUpload', id: data.id }))
|
||||||
.on('on_asset_update', (data: AssetResponseDto) => onEvent({ event: 'assetUpdate', id: data.id }))
|
.on('on_asset_update', (data: AssetResponseDto) => onEvent({ event: 'assetUpdate', id: data.id }))
|
||||||
|
.on('on_asset_hidden', (assetId: string) => onEvent({ event: 'assetHidden', id: assetId }))
|
||||||
.on('on_asset_delete', (assetId: string) => onEvent({ event: 'assetDelete', id: assetId }))
|
.on('on_asset_delete', (assetId: string) => onEvent({ event: 'assetDelete', id: assetId }))
|
||||||
.on('on_user_delete', (userId: string) => onEvent({ event: 'userDelete', id: userId }))
|
.on('on_user_delete', (userId: string) => onEvent({ event: 'userDelete', id: userId }))
|
||||||
.connect();
|
.connect();
|
||||||
@@ -398,14 +400,7 @@ export const utils = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const vector = Array.from({ length: 512 }, Math.random);
|
await client.query('INSERT INTO asset_faces ("assetId", "personId") VALUES ($1, $2)', [assetId, personId]);
|
||||||
const embedding = `[${vector.join(',')}]`;
|
|
||||||
|
|
||||||
await client.query('INSERT INTO asset_faces ("assetId", "personId", "embedding") VALUES ($1, $2, $3)', [
|
|
||||||
assetId,
|
|
||||||
personId,
|
|
||||||
embedding,
|
|
||||||
]);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
setPersonThumbnail: async (personId: string) => {
|
setPersonThumbnail: async (personId: string) => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
ARG DEVICE=cpu
|
ARG DEVICE=cpu
|
||||||
|
|
||||||
FROM python:3.11-bookworm@sha256:96de1ea4821d73fd2c1853d1fdc3cf794ccfe2fae4c3f08579e846de51760a61 as builder-cpu
|
FROM python:3.11-bookworm@sha256:7bec1574675e7fd9e3a540a03cd7d6811c59ca261bd300cd665369d8f435298a as builder-cpu
|
||||||
|
|
||||||
FROM openvino/ubuntu22_runtime:2023.3.0@sha256:176646df619032ea6c10faf842867119c393e7497b7f88b5e307e932a0fd5aa8 as builder-openvino
|
FROM openvino/ubuntu22_runtime:2023.3.0@sha256:176646df619032ea6c10faf842867119c393e7497b7f88b5e307e932a0fd5aa8 as builder-openvino
|
||||||
USER root
|
USER root
|
||||||
@@ -36,7 +36,7 @@ RUN python3 -m venv /opt/venv
|
|||||||
COPY poetry.lock pyproject.toml ./
|
COPY poetry.lock pyproject.toml ./
|
||||||
RUN poetry install --sync --no-interaction --no-ansi --no-root --with ${DEVICE} --without dev
|
RUN poetry install --sync --no-interaction --no-ansi --no-root --with ${DEVICE} --without dev
|
||||||
|
|
||||||
FROM python:3.11-slim-bookworm@sha256:fc39d2e68b554c3f0a5cb8a776280c0b3d73b4c04b83dbade835e2a171ca27ef as prod-cpu
|
FROM python:3.11-slim-bookworm@sha256:17ec9dc2367aa748559d0212f34665ec4df801129de32db705ea34654b5bc77a as prod-cpu
|
||||||
|
|
||||||
FROM openvino/ubuntu22_runtime:2023.3.0@sha256:176646df619032ea6c10faf842867119c393e7497b7f88b5e307e932a0fd5aa8 as prod-openvino
|
FROM openvino/ubuntu22_runtime:2023.3.0@sha256:176646df619032ea6c10faf842867119c393e7497b7f88b5e307e932a0fd5aa8 as prod-openvino
|
||||||
USER root
|
USER root
|
||||||
|
|||||||
@@ -52,8 +52,6 @@ class Ann(metaclass=_Singleton):
|
|||||||
def __init__(self, log_level: int = 3, tuning_level: int = 1, tuning_file: str | None = None) -> None:
|
def __init__(self, log_level: int = 3, tuning_level: int = 1, tuning_file: str | None = None) -> None:
|
||||||
if not is_available:
|
if not is_available:
|
||||||
raise RuntimeError("libann is not available!")
|
raise RuntimeError("libann is not available!")
|
||||||
if tuning_file and not exists(tuning_file):
|
|
||||||
raise ValueError("tuning_file must point to an existing (possibly empty) file!")
|
|
||||||
if tuning_level == 0 and tuning_file is None:
|
if tuning_level == 0 and tuning_file is None:
|
||||||
raise ValueError("tuning_level == 0 reads existing tuning information and requires a tuning_file")
|
raise ValueError("tuning_level == 0 reads existing tuning information and requires a tuning_file")
|
||||||
if tuning_level < 0 or tuning_level > 3:
|
if tuning_level < 0 or tuning_level > 3:
|
||||||
@@ -67,6 +65,12 @@ class Ann(metaclass=_Singleton):
|
|||||||
self.input_shapes: dict[int, tuple[tuple[int], ...]] = {}
|
self.input_shapes: dict[int, tuple[tuple[int], ...]] = {}
|
||||||
self.ann: int | None = None
|
self.ann: int | None = None
|
||||||
self.new()
|
self.new()
|
||||||
|
|
||||||
|
if self.tuning_file is not None:
|
||||||
|
# make sure tuning file exists (without clearing contents)
|
||||||
|
# once filled, the tuning file reduces the cost/time of the first
|
||||||
|
# inference after model load by 10s of seconds
|
||||||
|
open(self.tuning_file, "a").close()
|
||||||
|
|
||||||
def new(self) -> None:
|
def new(self) -> None:
|
||||||
if self.ann is None:
|
if self.ann is None:
|
||||||
@@ -95,17 +99,19 @@ class Ann(metaclass=_Singleton):
|
|||||||
model_path: str,
|
model_path: str,
|
||||||
fast_math: bool = True,
|
fast_math: bool = True,
|
||||||
fp16: bool = False,
|
fp16: bool = False,
|
||||||
save_cached_network: bool = False,
|
|
||||||
cached_network_path: str | None = None,
|
cached_network_path: str | None = None,
|
||||||
) -> int:
|
) -> int:
|
||||||
if not model_path.endswith((".armnn", ".tflite", ".onnx")):
|
if not model_path.endswith((".armnn", ".tflite", ".onnx")):
|
||||||
raise ValueError("model_path must be a file with extension .armnn, .tflite or .onnx")
|
raise ValueError("model_path must be a file with extension .armnn, .tflite or .onnx")
|
||||||
if not exists(model_path):
|
if not exists(model_path):
|
||||||
raise ValueError("model_path must point to an existing file!")
|
raise ValueError("model_path must point to an existing file!")
|
||||||
|
|
||||||
|
save_cached_network = False
|
||||||
if cached_network_path is not None and not exists(cached_network_path):
|
if cached_network_path is not None and not exists(cached_network_path):
|
||||||
raise ValueError("cached_network_path must point to an existing (possibly empty) file!")
|
save_cached_network = True
|
||||||
if save_cached_network and cached_network_path is None:
|
# create empty model cache file
|
||||||
raise ValueError("save_cached_network is True, cached_network_path must be specified!")
|
open(cached_network_path, "a").close()
|
||||||
|
|
||||||
net_id: int = libann.load(
|
net_id: int = libann.load(
|
||||||
self.ann,
|
self.ann,
|
||||||
model_path.encode(),
|
model_path.encode(),
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ from fastapi.testclient import TestClient
|
|||||||
from numpy.typing import NDArray
|
from numpy.typing import NDArray
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
|
from app.config import log
|
||||||
|
|
||||||
from .main import app
|
from .main import app
|
||||||
|
|
||||||
|
|
||||||
@@ -96,12 +98,77 @@ def clip_tokenizer_cfg() -> dict[str, Any]:
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="function")
|
@pytest.fixture(scope="function")
|
||||||
def providers(request: pytest.FixtureRequest) -> Iterator[dict[str, Any]]:
|
def providers(request: pytest.FixtureRequest) -> Iterator[mock.Mock]:
|
||||||
marker = request.node.get_closest_marker("providers")
|
marker = request.node.get_closest_marker("providers")
|
||||||
if marker is None:
|
if marker is None:
|
||||||
raise ValueError("Missing marker 'providers'")
|
raise ValueError("Missing marker 'providers'")
|
||||||
|
|
||||||
providers = marker.args[0]
|
providers = marker.args[0]
|
||||||
with mock.patch("app.models.base.ort.get_available_providers") as mocked:
|
with mock.patch("app.sessions.ort.ort.get_available_providers") as mocked:
|
||||||
mocked.return_value = providers
|
mocked.return_value = providers
|
||||||
yield providers
|
yield providers
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="function")
|
||||||
|
def ort_pybind() -> Iterator[mock.Mock]:
|
||||||
|
with mock.patch("app.sessions.ort.ort.capi._pybind_state") as mocked:
|
||||||
|
yield mocked
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="function")
|
||||||
|
def ov_device_ids(request: pytest.FixtureRequest, ort_pybind: mock.Mock) -> Iterator[mock.Mock]:
|
||||||
|
marker = request.node.get_closest_marker("ov_device_ids")
|
||||||
|
if marker is None:
|
||||||
|
raise ValueError("Missing marker 'ov_device_ids'")
|
||||||
|
ort_pybind.get_available_openvino_device_ids.return_value = marker.args[0]
|
||||||
|
return ort_pybind
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="function")
|
||||||
|
def ort_session() -> Iterator[mock.Mock]:
|
||||||
|
with mock.patch("app.sessions.ort.ort.InferenceSession") as mocked:
|
||||||
|
yield mocked
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="function")
|
||||||
|
def ann_session() -> Iterator[mock.Mock]:
|
||||||
|
with mock.patch("app.sessions.ann.Ann") as mocked:
|
||||||
|
yield mocked
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="function")
|
||||||
|
def rmtree() -> Iterator[mock.Mock]:
|
||||||
|
with mock.patch("app.models.base.rmtree", autospec=True) as mocked:
|
||||||
|
mocked.avoids_symlink_attacks = True
|
||||||
|
yield mocked
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="function")
|
||||||
|
def path() -> Iterator[mock.Mock]:
|
||||||
|
path = mock.MagicMock()
|
||||||
|
path.exists.return_value = True
|
||||||
|
path.is_dir.return_value = True
|
||||||
|
path.is_file.return_value = True
|
||||||
|
path.with_suffix.return_value = path
|
||||||
|
path.return_value = path
|
||||||
|
|
||||||
|
with mock.patch("app.models.base.Path", return_value=path) as mocked:
|
||||||
|
yield mocked
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="function")
|
||||||
|
def info() -> Iterator[mock.Mock]:
|
||||||
|
with mock.patch.object(log, "info") as mocked:
|
||||||
|
yield mocked
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="function")
|
||||||
|
def warning() -> Iterator[mock.Mock]:
|
||||||
|
with mock.patch.object(log, "warning") as mocked:
|
||||||
|
yield mocked
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="function")
|
||||||
|
def snapshot_download() -> Iterator[mock.Mock]:
|
||||||
|
with mock.patch("app.models.base.snapshot_download") as mocked:
|
||||||
|
yield mocked
|
||||||
|
|||||||
@@ -192,23 +192,18 @@ async def load(model: InferenceModel) -> InferenceModel:
|
|||||||
return model
|
return model
|
||||||
|
|
||||||
def _load(model: InferenceModel) -> InferenceModel:
|
def _load(model: InferenceModel) -> InferenceModel:
|
||||||
|
if model.load_attempts > 1:
|
||||||
|
raise HTTPException(500, f"Failed to load model '{model.model_name}'")
|
||||||
with lock:
|
with lock:
|
||||||
model.load()
|
model.load()
|
||||||
return model
|
return model
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await run(_load, model)
|
return await run(_load, model)
|
||||||
return model
|
|
||||||
except (OSError, InvalidProtobuf, BadZipFile, NoSuchFile):
|
except (OSError, InvalidProtobuf, BadZipFile, NoSuchFile):
|
||||||
log.warning(
|
log.warning(f"Failed to load {model.model_type.replace('_', ' ')} model '{model.model_name}'. Clearing cache.")
|
||||||
(
|
|
||||||
f"Failed to load {model.model_type.replace('_', ' ')} model '{model.model_name}'."
|
|
||||||
"Clearing cache and retrying."
|
|
||||||
)
|
|
||||||
)
|
|
||||||
model.clear_cache()
|
model.clear_cache()
|
||||||
await run(_load, model)
|
return await run(_load, model)
|
||||||
return model
|
|
||||||
|
|
||||||
|
|
||||||
async def idle_shutdown_task() -> None:
|
async def idle_shutdown_task() -> None:
|
||||||
|
|||||||
@@ -5,15 +5,14 @@ from pathlib import Path
|
|||||||
from shutil import rmtree
|
from shutil import rmtree
|
||||||
from typing import Any, ClassVar
|
from typing import Any, ClassVar
|
||||||
|
|
||||||
import onnxruntime as ort
|
|
||||||
from huggingface_hub import snapshot_download
|
from huggingface_hub import snapshot_download
|
||||||
|
|
||||||
import ann.ann
|
import ann.ann
|
||||||
from app.models.constants import SUPPORTED_PROVIDERS
|
from app.sessions.ort import OrtSession
|
||||||
|
|
||||||
from ..config import clean_name, log, settings
|
from ..config import clean_name, log, settings
|
||||||
from ..schemas import ModelFormat, ModelIdentity, ModelSession, ModelTask, ModelType
|
from ..schemas import ModelFormat, ModelIdentity, ModelSession, ModelTask, ModelType
|
||||||
from .ann import AnnSession
|
from ..sessions.ann import AnnSession
|
||||||
|
|
||||||
|
|
||||||
class InferenceModel(ABC):
|
class InferenceModel(ABC):
|
||||||
@@ -24,19 +23,17 @@ class InferenceModel(ABC):
|
|||||||
self,
|
self,
|
||||||
model_name: str,
|
model_name: str,
|
||||||
cache_dir: Path | str | None = None,
|
cache_dir: Path | str | None = None,
|
||||||
providers: list[str] | None = None,
|
|
||||||
provider_options: list[dict[str, Any]] | None = None,
|
|
||||||
sess_options: ort.SessionOptions | None = None,
|
|
||||||
preferred_format: ModelFormat | None = None,
|
preferred_format: ModelFormat | None = None,
|
||||||
|
session: ModelSession | None = None,
|
||||||
**model_kwargs: Any,
|
**model_kwargs: Any,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.loaded = False
|
self.loaded = session is not None
|
||||||
|
self.load_attempts = 0
|
||||||
self.model_name = clean_name(model_name)
|
self.model_name = clean_name(model_name)
|
||||||
self.cache_dir = Path(cache_dir) if cache_dir is not None else self.cache_dir_default
|
self.cache_dir = Path(cache_dir) if cache_dir is not None else self._cache_dir_default
|
||||||
self.providers = providers if providers is not None else self.providers_default
|
self.model_format = preferred_format if preferred_format is not None else self._model_format_default
|
||||||
self.provider_options = provider_options if provider_options is not None else self.provider_options_default
|
if session is not None:
|
||||||
self.sess_options = sess_options if sess_options is not None else self.sess_options_default
|
self.session = session
|
||||||
self.preferred_format = preferred_format if preferred_format is not None else self.preferred_format_default
|
|
||||||
|
|
||||||
def download(self) -> None:
|
def download(self) -> None:
|
||||||
if not self.cached:
|
if not self.cached:
|
||||||
@@ -48,9 +45,11 @@ class InferenceModel(ABC):
|
|||||||
def load(self) -> None:
|
def load(self) -> None:
|
||||||
if self.loaded:
|
if self.loaded:
|
||||||
return
|
return
|
||||||
|
self.load_attempts += 1
|
||||||
|
|
||||||
self.download()
|
self.download()
|
||||||
log.info(f"Loading {self.model_type.replace('-', ' ')} model '{self.model_name}' to memory")
|
attempt = f"Attempt #{self.load_attempts + 1} to load" if self.load_attempts else "Loading"
|
||||||
|
log.info(f"{attempt} {self.model_type.replace('-', ' ')} model '{self.model_name}' to memory")
|
||||||
self.session = self._load()
|
self.session = self._load()
|
||||||
self.loaded = True
|
self.loaded = True
|
||||||
|
|
||||||
@@ -67,7 +66,7 @@ class InferenceModel(ABC):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def _download(self) -> None:
|
def _download(self) -> None:
|
||||||
ignore_patterns = [] if self.preferred_format == ModelFormat.ARMNN else ["*.armnn"]
|
ignore_patterns = [] if self.model_format == ModelFormat.ARMNN else ["*.armnn"]
|
||||||
snapshot_download(
|
snapshot_download(
|
||||||
f"immich-app/{clean_name(self.model_name)}",
|
f"immich-app/{clean_name(self.model_name)}",
|
||||||
cache_dir=self.cache_dir,
|
cache_dir=self.cache_dir,
|
||||||
@@ -102,26 +101,11 @@ class InferenceModel(ABC):
|
|||||||
self.cache_dir.mkdir(parents=True, exist_ok=True)
|
self.cache_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
def _make_session(self, model_path: Path) -> ModelSession:
|
def _make_session(self, model_path: Path) -> ModelSession:
|
||||||
if not model_path.is_file():
|
|
||||||
onnx_path = model_path.with_suffix(".onnx")
|
|
||||||
if not onnx_path.is_file():
|
|
||||||
raise ValueError(f"Model path '{model_path}' does not exist")
|
|
||||||
|
|
||||||
log.warning(
|
|
||||||
f"Could not find model path '{model_path}'. " f"Falling back to ONNX model path '{onnx_path}' instead.",
|
|
||||||
)
|
|
||||||
model_path = onnx_path
|
|
||||||
|
|
||||||
match model_path.suffix:
|
match model_path.suffix:
|
||||||
case ".armnn":
|
case ".armnn":
|
||||||
session = AnnSession(model_path)
|
session: ModelSession = AnnSession(model_path)
|
||||||
case ".onnx":
|
case ".onnx":
|
||||||
session = ort.InferenceSession(
|
session = OrtSession(model_path)
|
||||||
model_path.as_posix(),
|
|
||||||
sess_options=self.sess_options,
|
|
||||||
providers=self.providers,
|
|
||||||
provider_options=self.provider_options,
|
|
||||||
)
|
|
||||||
case _:
|
case _:
|
||||||
raise ValueError(f"Unsupported model file type: {model_path.suffix}")
|
raise ValueError(f"Unsupported model file type: {model_path.suffix}")
|
||||||
return session
|
return session
|
||||||
@@ -132,7 +116,7 @@ class InferenceModel(ABC):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def model_path(self) -> Path:
|
def model_path(self) -> Path:
|
||||||
return self.model_dir / f"model.{self.preferred_format}"
|
return self.model_dir / f"model.{self.model_format}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def model_task(self) -> ModelTask:
|
def model_task(self) -> ModelTask:
|
||||||
@@ -151,7 +135,7 @@ class InferenceModel(ABC):
|
|||||||
self._cache_dir = cache_dir
|
self._cache_dir = cache_dir
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cache_dir_default(self) -> Path:
|
def _cache_dir_default(self) -> Path:
|
||||||
return settings.cache_folder / self.model_task.value / self.model_name
|
return settings.cache_folder / self.model_task.value / self.model_name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -159,95 +143,18 @@ class InferenceModel(ABC):
|
|||||||
return self.model_path.is_file()
|
return self.model_path.is_file()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def providers(self) -> list[str]:
|
def model_format(self) -> ModelFormat:
|
||||||
return self._providers
|
|
||||||
|
|
||||||
@providers.setter
|
|
||||||
def providers(self, providers: list[str]) -> None:
|
|
||||||
log.info(
|
|
||||||
(f"Setting '{self.model_name}' execution providers to {providers}, " "in descending order of preference"),
|
|
||||||
)
|
|
||||||
self._providers = providers
|
|
||||||
|
|
||||||
@property
|
|
||||||
def providers_default(self) -> list[str]:
|
|
||||||
available_providers = set(ort.get_available_providers())
|
|
||||||
log.debug(f"Available ORT providers: {available_providers}")
|
|
||||||
if (openvino := "OpenVINOExecutionProvider") in available_providers:
|
|
||||||
device_ids: list[str] = ort.capi._pybind_state.get_available_openvino_device_ids()
|
|
||||||
log.debug(f"Available OpenVINO devices: {device_ids}")
|
|
||||||
|
|
||||||
gpu_devices = [device_id for device_id in device_ids if device_id.startswith("GPU")]
|
|
||||||
if not gpu_devices:
|
|
||||||
log.warning("No GPU device found in OpenVINO. Falling back to CPU.")
|
|
||||||
available_providers.remove(openvino)
|
|
||||||
return [provider for provider in SUPPORTED_PROVIDERS if provider in available_providers]
|
|
||||||
|
|
||||||
@property
|
|
||||||
def provider_options(self) -> list[dict[str, Any]]:
|
|
||||||
return self._provider_options
|
|
||||||
|
|
||||||
@provider_options.setter
|
|
||||||
def provider_options(self, provider_options: list[dict[str, Any]]) -> None:
|
|
||||||
log.debug(f"Setting execution provider options to {provider_options}")
|
|
||||||
self._provider_options = provider_options
|
|
||||||
|
|
||||||
@property
|
|
||||||
def provider_options_default(self) -> list[dict[str, Any]]:
|
|
||||||
options = []
|
|
||||||
for provider in self.providers:
|
|
||||||
match provider:
|
|
||||||
case "CPUExecutionProvider" | "CUDAExecutionProvider":
|
|
||||||
option = {"arena_extend_strategy": "kSameAsRequested"}
|
|
||||||
case "OpenVINOExecutionProvider":
|
|
||||||
option = {"device_type": "GPU_FP32", "cache_dir": (self.cache_dir / "openvino").as_posix()}
|
|
||||||
case _:
|
|
||||||
option = {}
|
|
||||||
options.append(option)
|
|
||||||
return options
|
|
||||||
|
|
||||||
@property
|
|
||||||
def sess_options(self) -> ort.SessionOptions:
|
|
||||||
return self._sess_options
|
|
||||||
|
|
||||||
@sess_options.setter
|
|
||||||
def sess_options(self, sess_options: ort.SessionOptions) -> None:
|
|
||||||
log.debug(f"Setting execution_mode to {sess_options.execution_mode.name}")
|
|
||||||
log.debug(f"Setting inter_op_num_threads to {sess_options.inter_op_num_threads}")
|
|
||||||
log.debug(f"Setting intra_op_num_threads to {sess_options.intra_op_num_threads}")
|
|
||||||
self._sess_options = sess_options
|
|
||||||
|
|
||||||
@property
|
|
||||||
def sess_options_default(self) -> ort.SessionOptions:
|
|
||||||
sess_options = ort.SessionOptions()
|
|
||||||
sess_options.enable_cpu_mem_arena = False
|
|
||||||
|
|
||||||
# avoid thread contention between models
|
|
||||||
if settings.model_inter_op_threads > 0:
|
|
||||||
sess_options.inter_op_num_threads = settings.model_inter_op_threads
|
|
||||||
# these defaults work well for CPU, but bottleneck GPU
|
|
||||||
elif settings.model_inter_op_threads == 0 and self.providers == ["CPUExecutionProvider"]:
|
|
||||||
sess_options.inter_op_num_threads = 1
|
|
||||||
|
|
||||||
if settings.model_intra_op_threads > 0:
|
|
||||||
sess_options.intra_op_num_threads = settings.model_intra_op_threads
|
|
||||||
elif settings.model_intra_op_threads == 0 and self.providers == ["CPUExecutionProvider"]:
|
|
||||||
sess_options.intra_op_num_threads = 2
|
|
||||||
|
|
||||||
if sess_options.inter_op_num_threads > 1:
|
|
||||||
sess_options.execution_mode = ort.ExecutionMode.ORT_PARALLEL
|
|
||||||
|
|
||||||
return sess_options
|
|
||||||
|
|
||||||
@property
|
|
||||||
def preferred_format(self) -> ModelFormat:
|
|
||||||
return self._preferred_format
|
return self._preferred_format
|
||||||
|
|
||||||
@preferred_format.setter
|
@model_format.setter
|
||||||
def preferred_format(self, preferred_format: ModelFormat) -> None:
|
def model_format(self, preferred_format: ModelFormat) -> None:
|
||||||
log.debug(f"Setting preferred format to {preferred_format}")
|
log.debug(f"Setting preferred format to {preferred_format}")
|
||||||
self._preferred_format = preferred_format
|
self._preferred_format = preferred_format
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def preferred_format_default(self) -> ModelFormat:
|
def _model_format_default(self) -> ModelFormat:
|
||||||
return ModelFormat.ARMNN if ann.ann.is_available and settings.ann else ModelFormat.ONNX
|
prefer_ann = ann.ann.is_available and settings.ann
|
||||||
|
ann_exists = (self.model_dir / "model.armnn").is_file()
|
||||||
|
if prefer_ann and not ann_exists:
|
||||||
|
log.warning(f"ARM NN is available, but '{self.model_name}' does not support ARM NN. Falling back to ONNX.")
|
||||||
|
return ModelFormat.ARMNN if prefer_ann and ann_exists else ModelFormat.ONNX
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ from typing import Any
|
|||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import onnx
|
import onnx
|
||||||
import onnxruntime as ort
|
|
||||||
from insightface.model_zoo import ArcFaceONNX
|
from insightface.model_zoo import ArcFaceONNX
|
||||||
from insightface.utils.face_align import norm_crop
|
from insightface.utils.face_align import norm_crop
|
||||||
from numpy.typing import NDArray
|
from numpy.typing import NDArray
|
||||||
@@ -13,7 +12,8 @@ from PIL import Image
|
|||||||
from app.config import clean_name, log
|
from app.config import clean_name, log
|
||||||
from app.models.base import InferenceModel
|
from app.models.base import InferenceModel
|
||||||
from app.models.transforms import decode_cv2
|
from app.models.transforms import decode_cv2
|
||||||
from app.schemas import FaceDetectionOutput, FacialRecognitionOutput, ModelSession, ModelTask, ModelType
|
from app.schemas import FaceDetectionOutput, FacialRecognitionOutput, ModelFormat, ModelSession, ModelTask, ModelType
|
||||||
|
from app.sessions import has_batch_axis
|
||||||
|
|
||||||
|
|
||||||
class FaceRecognizer(InferenceModel):
|
class FaceRecognizer(InferenceModel):
|
||||||
@@ -27,13 +27,14 @@ class FaceRecognizer(InferenceModel):
|
|||||||
cache_dir: Path | str | None = None,
|
cache_dir: Path | str | None = None,
|
||||||
**model_kwargs: Any,
|
**model_kwargs: Any,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.min_score = model_kwargs.pop("minScore", min_score)
|
|
||||||
super().__init__(clean_name(model_name), cache_dir, **model_kwargs)
|
super().__init__(clean_name(model_name), cache_dir, **model_kwargs)
|
||||||
|
self.min_score = model_kwargs.pop("minScore", min_score)
|
||||||
|
self.batch = self.model_format == ModelFormat.ONNX
|
||||||
|
|
||||||
def _load(self) -> ModelSession:
|
def _load(self) -> ModelSession:
|
||||||
session = self._make_session(self.model_path)
|
session = self._make_session(self.model_path)
|
||||||
if not self._has_batch_dim(session):
|
if self.model_format == ModelFormat.ONNX and not has_batch_axis(session):
|
||||||
self._add_batch_dim(self.model_path)
|
self._add_batch_axis(self.model_path)
|
||||||
session = self._make_session(self.model_path)
|
session = self._make_session(self.model_path)
|
||||||
self.model = ArcFaceONNX(
|
self.model = ArcFaceONNX(
|
||||||
self.model_path.with_suffix(".onnx").as_posix(),
|
self.model_path.with_suffix(".onnx").as_posix(),
|
||||||
@@ -47,9 +48,20 @@ class FaceRecognizer(InferenceModel):
|
|||||||
if faces["boxes"].shape[0] == 0:
|
if faces["boxes"].shape[0] == 0:
|
||||||
return []
|
return []
|
||||||
inputs = decode_cv2(inputs)
|
inputs = decode_cv2(inputs)
|
||||||
embeddings: NDArray[np.float32] = self.model.get_feat(self._crop(inputs, faces))
|
cropped_faces = self._crop(inputs, faces)
|
||||||
|
embeddings = self._predict_batch(cropped_faces) if self.batch else self._predict_single(cropped_faces)
|
||||||
return self.postprocess(faces, embeddings)
|
return self.postprocess(faces, embeddings)
|
||||||
|
|
||||||
|
def _predict_batch(self, cropped_faces: list[NDArray[np.uint8]]) -> NDArray[np.float32]:
|
||||||
|
embeddings: NDArray[np.float32] = self.model.get_feat(cropped_faces)
|
||||||
|
return embeddings
|
||||||
|
|
||||||
|
def _predict_single(self, cropped_faces: list[NDArray[np.uint8]]) -> NDArray[np.float32]:
|
||||||
|
embeddings: list[NDArray[np.float32]] = []
|
||||||
|
for face in cropped_faces:
|
||||||
|
embeddings.append(self.model.get_feat(face))
|
||||||
|
return np.concatenate(embeddings, axis=0)
|
||||||
|
|
||||||
def postprocess(self, faces: FaceDetectionOutput, embeddings: NDArray[np.float32]) -> FacialRecognitionOutput:
|
def postprocess(self, faces: FaceDetectionOutput, embeddings: NDArray[np.float32]) -> FacialRecognitionOutput:
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@@ -63,11 +75,8 @@ class FaceRecognizer(InferenceModel):
|
|||||||
def _crop(self, image: NDArray[np.uint8], faces: FaceDetectionOutput) -> list[NDArray[np.uint8]]:
|
def _crop(self, image: NDArray[np.uint8], faces: FaceDetectionOutput) -> list[NDArray[np.uint8]]:
|
||||||
return [norm_crop(image, landmark) for landmark in faces["landmarks"]]
|
return [norm_crop(image, landmark) for landmark in faces["landmarks"]]
|
||||||
|
|
||||||
def _has_batch_dim(self, session: ort.InferenceSession) -> bool:
|
def _add_batch_axis(self, model_path: Path) -> None:
|
||||||
return not isinstance(session, ort.InferenceSession) or session.get_inputs()[0].shape[0] == "batch"
|
log.debug(f"Adding batch axis to model {model_path}")
|
||||||
|
|
||||||
def _add_batch_dim(self, model_path: Path) -> None:
|
|
||||||
log.debug(f"Adding batch dimension to model {model_path}")
|
|
||||||
proto = onnx.load(model_path)
|
proto = onnx.load(model_path)
|
||||||
static_input_dims = [shape.dim_value for shape in proto.graph.input[0].type.tensor_type.shape.dim[1:]]
|
static_input_dims = [shape.dim_value for shape in proto.graph.input[0].type.tensor_type.shape.dim[1:]]
|
||||||
static_output_dims = [shape.dim_value for shape in proto.graph.output[0].type.tensor_type.shape.dim[1:]]
|
static_output_dims = [shape.dim_value for shape in proto.graph.output[0].type.tensor_type.shape.dim[1:]]
|
||||||
|
|||||||
@@ -54,6 +54,14 @@ class ModelSource(StrEnum):
|
|||||||
ModelIdentity = tuple[ModelType, ModelTask]
|
ModelIdentity = tuple[ModelType, ModelTask]
|
||||||
|
|
||||||
|
|
||||||
|
class SessionNode(Protocol):
|
||||||
|
@property
|
||||||
|
def name(self) -> str | None: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def shape(self) -> tuple[int, ...]: ...
|
||||||
|
|
||||||
|
|
||||||
class ModelSession(Protocol):
|
class ModelSession(Protocol):
|
||||||
def run(
|
def run(
|
||||||
self,
|
self,
|
||||||
@@ -62,6 +70,10 @@ class ModelSession(Protocol):
|
|||||||
run_options: Any = None,
|
run_options: Any = None,
|
||||||
) -> list[npt.NDArray[np.float32]]: ...
|
) -> list[npt.NDArray[np.float32]]: ...
|
||||||
|
|
||||||
|
def get_inputs(self) -> list[SessionNode]: ...
|
||||||
|
|
||||||
|
def get_outputs(self) -> list[SessionNode]: ...
|
||||||
|
|
||||||
|
|
||||||
class HasProfiling(Protocol):
|
class HasProfiling(Protocol):
|
||||||
profiling: dict[str, float]
|
profiling: dict[str, float]
|
||||||
|
|||||||
5
machine-learning/app/sessions/__init__.py
Normal file
5
machine-learning/app/sessions/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
from app.schemas import ModelSession
|
||||||
|
|
||||||
|
|
||||||
|
def has_batch_axis(session: ModelSession) -> bool:
|
||||||
|
return not isinstance(session.get_inputs()[0].shape[0], int) or session.get_inputs()[0].shape[0] < 0
|
||||||
@@ -7,6 +7,7 @@ import numpy as np
|
|||||||
from numpy.typing import NDArray
|
from numpy.typing import NDArray
|
||||||
|
|
||||||
from ann.ann import Ann
|
from ann.ann import Ann
|
||||||
|
from app.schemas import SessionNode
|
||||||
|
|
||||||
from ..config import log, settings
|
from ..config import log, settings
|
||||||
|
|
||||||
@@ -16,27 +17,15 @@ class AnnSession:
|
|||||||
Wrapper for ANN to be drop-in replacement for ONNX session.
|
Wrapper for ANN to be drop-in replacement for ONNX session.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, model_path: Path):
|
def __init__(self, model_path: Path, cache_dir: Path = settings.cache_folder) -> None:
|
||||||
tuning_file = Path(settings.cache_folder) / "gpu-tuning.ann"
|
self.model_path = model_path
|
||||||
with tuning_file.open(mode="a"):
|
self.cache_dir = cache_dir
|
||||||
# make sure tuning file exists (without clearing contents)
|
self.ann = Ann(tuning_level=3, tuning_file=(cache_dir / "gpu-tuning.ann").as_posix())
|
||||||
# once filled, the tuning file reduces the cost/time of the first
|
|
||||||
# inference after model load by 10s of seconds
|
|
||||||
pass
|
|
||||||
self.ann = Ann(tuning_level=3, tuning_file=tuning_file.as_posix())
|
|
||||||
log.info("Loading ANN model %s ...", model_path)
|
|
||||||
cache_file = model_path.with_suffix(".anncache")
|
|
||||||
save = False
|
|
||||||
if not cache_file.is_file():
|
|
||||||
save = True
|
|
||||||
with cache_file.open(mode="a"):
|
|
||||||
# create empty model cache file
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
log.info("Loading ANN model %s ...", model_path)
|
||||||
self.model = self.ann.load(
|
self.model = self.ann.load(
|
||||||
model_path.as_posix(),
|
model_path.as_posix(),
|
||||||
save_cached_network=save,
|
cached_network_path=model_path.with_suffix(".anncache").as_posix(),
|
||||||
cached_network_path=cache_file.as_posix(),
|
|
||||||
)
|
)
|
||||||
log.info("Loaded ANN model with ID %d", self.model)
|
log.info("Loaded ANN model with ID %d", self.model)
|
||||||
|
|
||||||
@@ -45,11 +34,11 @@ class AnnSession:
|
|||||||
log.info("Unloaded ANN model %d", self.model)
|
log.info("Unloaded ANN model %d", self.model)
|
||||||
self.ann.destroy()
|
self.ann.destroy()
|
||||||
|
|
||||||
def get_inputs(self) -> list[AnnNode]:
|
def get_inputs(self) -> list[SessionNode]:
|
||||||
shapes = self.ann.input_shapes[self.model]
|
shapes = self.ann.input_shapes[self.model]
|
||||||
return [AnnNode(None, s) for s in shapes]
|
return [AnnNode(None, s) for s in shapes]
|
||||||
|
|
||||||
def get_outputs(self) -> list[AnnNode]:
|
def get_outputs(self) -> list[SessionNode]:
|
||||||
shapes = self.ann.output_shapes[self.model]
|
shapes = self.ann.output_shapes[self.model]
|
||||||
return [AnnNode(None, s) for s in shapes]
|
return [AnnNode(None, s) for s in shapes]
|
||||||
|
|
||||||
129
machine-learning/app/sessions/ort.py
Normal file
129
machine-learning/app/sessions/ort.py
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
import onnxruntime as ort
|
||||||
|
from numpy.typing import NDArray
|
||||||
|
|
||||||
|
from app.models.constants import SUPPORTED_PROVIDERS
|
||||||
|
from app.schemas import SessionNode
|
||||||
|
|
||||||
|
from ..config import log, settings
|
||||||
|
|
||||||
|
|
||||||
|
class OrtSession:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
model_path: Path | str,
|
||||||
|
providers: list[str] | None = None,
|
||||||
|
provider_options: list[dict[str, Any]] | None = None,
|
||||||
|
sess_options: ort.SessionOptions | None = None,
|
||||||
|
):
|
||||||
|
self.model_path = Path(model_path)
|
||||||
|
self.providers = providers if providers is not None else self._providers_default
|
||||||
|
self.provider_options = provider_options if provider_options is not None else self._provider_options_default
|
||||||
|
self.sess_options = sess_options if sess_options is not None else self._sess_options_default
|
||||||
|
self.session = ort.InferenceSession(
|
||||||
|
self.model_path.as_posix(),
|
||||||
|
providers=self.providers,
|
||||||
|
provider_options=self.provider_options,
|
||||||
|
sess_options=self.sess_options,
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_inputs(self) -> list[SessionNode]:
|
||||||
|
inputs: list[SessionNode] = self.session.get_inputs()
|
||||||
|
return inputs
|
||||||
|
|
||||||
|
def get_outputs(self) -> list[SessionNode]:
|
||||||
|
outputs: list[SessionNode] = self.session.get_outputs()
|
||||||
|
return outputs
|
||||||
|
|
||||||
|
def run(
|
||||||
|
self,
|
||||||
|
output_names: list[str] | None,
|
||||||
|
input_feed: dict[str, NDArray[np.float32]] | dict[str, NDArray[np.int32]],
|
||||||
|
run_options: Any = None,
|
||||||
|
) -> list[NDArray[np.float32]]:
|
||||||
|
outputs: list[NDArray[np.float32]] = self.session.run(output_names, input_feed, run_options)
|
||||||
|
return outputs
|
||||||
|
|
||||||
|
@property
|
||||||
|
def providers(self) -> list[str]:
|
||||||
|
return self._providers
|
||||||
|
|
||||||
|
@providers.setter
|
||||||
|
def providers(self, providers: list[str]) -> None:
|
||||||
|
log.info(f"Setting execution providers to {providers}, in descending order of preference")
|
||||||
|
self._providers = providers
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _providers_default(self) -> list[str]:
|
||||||
|
available_providers = set(ort.get_available_providers())
|
||||||
|
log.debug(f"Available ORT providers: {available_providers}")
|
||||||
|
if (openvino := "OpenVINOExecutionProvider") in available_providers:
|
||||||
|
device_ids: list[str] = ort.capi._pybind_state.get_available_openvino_device_ids()
|
||||||
|
log.debug(f"Available OpenVINO devices: {device_ids}")
|
||||||
|
|
||||||
|
gpu_devices = [device_id for device_id in device_ids if device_id.startswith("GPU")]
|
||||||
|
if not gpu_devices:
|
||||||
|
log.warning("No GPU device found in OpenVINO. Falling back to CPU.")
|
||||||
|
available_providers.remove(openvino)
|
||||||
|
return [provider for provider in SUPPORTED_PROVIDERS if provider in available_providers]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def provider_options(self) -> list[dict[str, Any]]:
|
||||||
|
return self._provider_options
|
||||||
|
|
||||||
|
@provider_options.setter
|
||||||
|
def provider_options(self, provider_options: list[dict[str, Any]]) -> None:
|
||||||
|
log.debug(f"Setting execution provider options to {provider_options}")
|
||||||
|
self._provider_options = provider_options
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _provider_options_default(self) -> list[dict[str, Any]]:
|
||||||
|
options = []
|
||||||
|
for provider in self.providers:
|
||||||
|
match provider:
|
||||||
|
case "CPUExecutionProvider" | "CUDAExecutionProvider":
|
||||||
|
option = {"arena_extend_strategy": "kSameAsRequested"}
|
||||||
|
case "OpenVINOExecutionProvider":
|
||||||
|
option = {"device_type": "GPU_FP32", "cache_dir": (self.model_path.parent / "openvino").as_posix()}
|
||||||
|
case _:
|
||||||
|
option = {}
|
||||||
|
options.append(option)
|
||||||
|
return options
|
||||||
|
|
||||||
|
@property
|
||||||
|
def sess_options(self) -> ort.SessionOptions:
|
||||||
|
return self._sess_options
|
||||||
|
|
||||||
|
@sess_options.setter
|
||||||
|
def sess_options(self, sess_options: ort.SessionOptions) -> None:
|
||||||
|
log.debug(f"Setting execution_mode to {sess_options.execution_mode.name}")
|
||||||
|
log.debug(f"Setting inter_op_num_threads to {sess_options.inter_op_num_threads}")
|
||||||
|
log.debug(f"Setting intra_op_num_threads to {sess_options.intra_op_num_threads}")
|
||||||
|
self._sess_options = sess_options
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _sess_options_default(self) -> ort.SessionOptions:
|
||||||
|
sess_options = ort.SessionOptions()
|
||||||
|
sess_options.enable_cpu_mem_arena = False
|
||||||
|
|
||||||
|
# avoid thread contention between models
|
||||||
|
if settings.model_inter_op_threads > 0:
|
||||||
|
sess_options.inter_op_num_threads = settings.model_inter_op_threads
|
||||||
|
# these defaults work well for CPU, but bottleneck GPU
|
||||||
|
elif settings.model_inter_op_threads == 0 and self.providers == ["CPUExecutionProvider"]:
|
||||||
|
sess_options.inter_op_num_threads = 1
|
||||||
|
|
||||||
|
if settings.model_intra_op_threads > 0:
|
||||||
|
sess_options.intra_op_num_threads = settings.model_intra_op_threads
|
||||||
|
elif settings.model_intra_op_threads == 0 and self.providers == ["CPUExecutionProvider"]:
|
||||||
|
sess_options.intra_op_num_threads = 2
|
||||||
|
|
||||||
|
if sess_options.inter_op_num_threads > 1:
|
||||||
|
sess_options.execution_mode = ort.ExecutionMode.ORT_PARALLEL
|
||||||
|
|
||||||
|
return sess_options
|
||||||
@@ -11,6 +11,7 @@ import cv2
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import onnxruntime as ort
|
import onnxruntime as ort
|
||||||
import pytest
|
import pytest
|
||||||
|
from fastapi import HTTPException
|
||||||
from fastapi.testclient import TestClient
|
from fastapi.testclient import TestClient
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from pytest import MonkeyPatch
|
from pytest import MonkeyPatch
|
||||||
@@ -21,129 +22,16 @@ from app.models.clip.textual import MClipTextualEncoder, OpenClipTextualEncoder
|
|||||||
from app.models.clip.visual import OpenClipVisualEncoder
|
from app.models.clip.visual import OpenClipVisualEncoder
|
||||||
from app.models.facial_recognition.detection import FaceDetector
|
from app.models.facial_recognition.detection import FaceDetector
|
||||||
from app.models.facial_recognition.recognition import FaceRecognizer
|
from app.models.facial_recognition.recognition import FaceRecognizer
|
||||||
|
from app.sessions.ann import AnnSession
|
||||||
|
from app.sessions.ort import OrtSession
|
||||||
|
|
||||||
from .config import Settings, log, settings
|
from .config import Settings, settings
|
||||||
from .models.base import InferenceModel
|
from .models.base import InferenceModel
|
||||||
from .models.cache import ModelCache
|
from .models.cache import ModelCache
|
||||||
from .schemas import ModelFormat, ModelTask, ModelType
|
from .schemas import ModelFormat, ModelTask, ModelType
|
||||||
|
|
||||||
|
|
||||||
class TestBase:
|
class TestBase:
|
||||||
CPU_EP = ["CPUExecutionProvider"]
|
|
||||||
CUDA_EP = ["CUDAExecutionProvider", "CPUExecutionProvider"]
|
|
||||||
OV_EP = ["OpenVINOExecutionProvider", "CPUExecutionProvider"]
|
|
||||||
CUDA_EP_OUT_OF_ORDER = ["CPUExecutionProvider", "CUDAExecutionProvider"]
|
|
||||||
TRT_EP = ["TensorrtExecutionProvider", "CUDAExecutionProvider", "CPUExecutionProvider"]
|
|
||||||
|
|
||||||
@pytest.mark.providers(CPU_EP)
|
|
||||||
def test_sets_cpu_provider(self, providers: list[str]) -> None:
|
|
||||||
encoder = OpenClipTextualEncoder("ViT-B-32__openai")
|
|
||||||
|
|
||||||
assert encoder.providers == self.CPU_EP
|
|
||||||
|
|
||||||
@pytest.mark.providers(CUDA_EP)
|
|
||||||
def test_sets_cuda_provider_if_available(self, providers: list[str]) -> None:
|
|
||||||
encoder = OpenClipTextualEncoder("ViT-B-32__openai")
|
|
||||||
|
|
||||||
assert encoder.providers == self.CUDA_EP
|
|
||||||
|
|
||||||
@pytest.mark.providers(OV_EP)
|
|
||||||
def test_sets_openvino_provider_if_available(self, providers: list[str], mocker: MockerFixture) -> None:
|
|
||||||
mocked = mocker.patch("app.models.base.ort.capi._pybind_state")
|
|
||||||
mocked.get_available_openvino_device_ids.return_value = ["GPU.0", "CPU"]
|
|
||||||
|
|
||||||
encoder = OpenClipTextualEncoder("ViT-B-32__openai")
|
|
||||||
|
|
||||||
assert encoder.providers == self.OV_EP
|
|
||||||
|
|
||||||
@pytest.mark.providers(OV_EP)
|
|
||||||
def test_avoids_openvino_if_gpu_not_available(self, providers: list[str], mocker: MockerFixture) -> None:
|
|
||||||
mocked = mocker.patch("app.models.base.ort.capi._pybind_state")
|
|
||||||
mocked.get_available_openvino_device_ids.return_value = ["CPU"]
|
|
||||||
|
|
||||||
encoder = OpenClipTextualEncoder("ViT-B-32__openai")
|
|
||||||
|
|
||||||
assert encoder.providers == self.CPU_EP
|
|
||||||
|
|
||||||
@pytest.mark.providers(CUDA_EP_OUT_OF_ORDER)
|
|
||||||
def test_sets_providers_in_correct_order(self, providers: list[str]) -> None:
|
|
||||||
encoder = OpenClipTextualEncoder("ViT-B-32__openai")
|
|
||||||
|
|
||||||
assert encoder.providers == self.CUDA_EP
|
|
||||||
|
|
||||||
@pytest.mark.providers(TRT_EP)
|
|
||||||
def test_ignores_unsupported_providers(self, providers: list[str]) -> None:
|
|
||||||
encoder = OpenClipTextualEncoder("ViT-B-32__openai")
|
|
||||||
|
|
||||||
assert encoder.providers == self.CUDA_EP
|
|
||||||
|
|
||||||
def test_sets_provider_kwarg(self) -> None:
|
|
||||||
providers = ["CUDAExecutionProvider"]
|
|
||||||
encoder = OpenClipTextualEncoder("ViT-B-32__openai", providers=providers)
|
|
||||||
|
|
||||||
assert encoder.providers == providers
|
|
||||||
|
|
||||||
def test_sets_default_provider_options(self, mocker: MockerFixture) -> None:
|
|
||||||
mocked = mocker.patch("app.models.base.ort.capi._pybind_state")
|
|
||||||
mocked.get_available_openvino_device_ids.return_value = ["GPU.0", "CPU"]
|
|
||||||
|
|
||||||
encoder = OpenClipTextualEncoder(
|
|
||||||
"ViT-B-32__openai", providers=["OpenVINOExecutionProvider", "CPUExecutionProvider"]
|
|
||||||
)
|
|
||||||
|
|
||||||
assert encoder.provider_options == [
|
|
||||||
{"device_type": "GPU_FP32", "cache_dir": (encoder.cache_dir / "openvino").as_posix()},
|
|
||||||
{"arena_extend_strategy": "kSameAsRequested"},
|
|
||||||
]
|
|
||||||
|
|
||||||
def test_sets_provider_options_kwarg(self) -> None:
|
|
||||||
encoder = OpenClipTextualEncoder(
|
|
||||||
"ViT-B-32__openai",
|
|
||||||
providers=["OpenVINOExecutionProvider", "CPUExecutionProvider"],
|
|
||||||
provider_options=[],
|
|
||||||
)
|
|
||||||
|
|
||||||
assert encoder.provider_options == []
|
|
||||||
|
|
||||||
def test_sets_default_sess_options(self) -> None:
|
|
||||||
encoder = OpenClipTextualEncoder("ViT-B-32__openai")
|
|
||||||
|
|
||||||
assert encoder.sess_options.execution_mode == ort.ExecutionMode.ORT_SEQUENTIAL
|
|
||||||
assert encoder.sess_options.inter_op_num_threads == 1
|
|
||||||
assert encoder.sess_options.intra_op_num_threads == 2
|
|
||||||
assert encoder.sess_options.enable_cpu_mem_arena is False
|
|
||||||
|
|
||||||
def test_sets_default_sess_options_does_not_set_threads_if_non_cpu_and_default_threads(self) -> None:
|
|
||||||
encoder = OpenClipTextualEncoder(
|
|
||||||
"ViT-B-32__openai", providers=["CUDAExecutionProvider", "CPUExecutionProvider"]
|
|
||||||
)
|
|
||||||
|
|
||||||
assert encoder.sess_options.inter_op_num_threads == 0
|
|
||||||
assert encoder.sess_options.intra_op_num_threads == 0
|
|
||||||
|
|
||||||
def test_sets_default_sess_options_sets_threads_if_non_cpu_and_set_threads(self, mocker: MockerFixture) -> None:
|
|
||||||
mock_settings = mocker.patch("app.models.base.settings", autospec=True)
|
|
||||||
mock_settings.model_inter_op_threads = 2
|
|
||||||
mock_settings.model_intra_op_threads = 4
|
|
||||||
|
|
||||||
encoder = OpenClipTextualEncoder(
|
|
||||||
"ViT-B-32__openai", providers=["CUDAExecutionProvider", "CPUExecutionProvider"]
|
|
||||||
)
|
|
||||||
|
|
||||||
assert encoder.sess_options.inter_op_num_threads == 2
|
|
||||||
assert encoder.sess_options.intra_op_num_threads == 4
|
|
||||||
|
|
||||||
def test_sets_sess_options_kwarg(self) -> None:
|
|
||||||
sess_options = ort.SessionOptions()
|
|
||||||
encoder = OpenClipTextualEncoder(
|
|
||||||
"ViT-B-32__openai",
|
|
||||||
providers=["OpenVINOExecutionProvider", "CPUExecutionProvider"],
|
|
||||||
provider_options=[],
|
|
||||||
sess_options=sess_options,
|
|
||||||
)
|
|
||||||
|
|
||||||
assert sess_options is encoder.sess_options
|
|
||||||
|
|
||||||
def test_sets_default_cache_dir(self) -> None:
|
def test_sets_default_cache_dir(self) -> None:
|
||||||
encoder = OpenClipTextualEncoder("ViT-B-32__openai")
|
encoder = OpenClipTextualEncoder("ViT-B-32__openai")
|
||||||
|
|
||||||
@@ -161,15 +49,16 @@ class TestBase:
|
|||||||
|
|
||||||
encoder = OpenClipTextualEncoder("ViT-B-32__openai")
|
encoder = OpenClipTextualEncoder("ViT-B-32__openai")
|
||||||
|
|
||||||
assert encoder.preferred_format == ModelFormat.ONNX
|
assert encoder.model_format == ModelFormat.ONNX
|
||||||
|
|
||||||
def test_sets_default_preferred_format_to_armnn_if_available(self, mocker: MockerFixture) -> None:
|
def test_sets_default_preferred_format_to_armnn_if_available(self, path: mock.Mock, mocker: MockerFixture) -> None:
|
||||||
mocker.patch.object(settings, "ann", True)
|
mocker.patch.object(settings, "ann", True)
|
||||||
mocker.patch("ann.ann.is_available", True)
|
mocker.patch("ann.ann.is_available", True)
|
||||||
|
path.suffix = ".armnn"
|
||||||
|
|
||||||
encoder = OpenClipTextualEncoder("ViT-B-32__openai")
|
encoder = OpenClipTextualEncoder("ViT-B-32__openai", cache_dir=path)
|
||||||
|
|
||||||
assert encoder.preferred_format == ModelFormat.ARMNN
|
assert encoder.model_format == ModelFormat.ARMNN
|
||||||
|
|
||||||
def test_sets_preferred_format_kwarg(self, mocker: MockerFixture) -> None:
|
def test_sets_preferred_format_kwarg(self, mocker: MockerFixture) -> None:
|
||||||
mocker.patch.object(settings, "ann", False)
|
mocker.patch.object(settings, "ann", False)
|
||||||
@@ -177,7 +66,7 @@ class TestBase:
|
|||||||
|
|
||||||
encoder = OpenClipTextualEncoder("ViT-B-32__openai", preferred_format=ModelFormat.ARMNN)
|
encoder = OpenClipTextualEncoder("ViT-B-32__openai", preferred_format=ModelFormat.ARMNN)
|
||||||
|
|
||||||
assert encoder.preferred_format == ModelFormat.ARMNN
|
assert encoder.model_format == ModelFormat.ARMNN
|
||||||
|
|
||||||
def test_casts_cache_dir_string_to_path(self) -> None:
|
def test_casts_cache_dir_string_to_path(self) -> None:
|
||||||
cache_dir = "/test_cache"
|
cache_dir = "/test_cache"
|
||||||
@@ -185,120 +74,53 @@ class TestBase:
|
|||||||
|
|
||||||
assert encoder.cache_dir == Path(cache_dir)
|
assert encoder.cache_dir == Path(cache_dir)
|
||||||
|
|
||||||
def test_clear_cache(self, mocker: MockerFixture) -> None:
|
def test_clear_cache(self, rmtree: mock.Mock, path: mock.Mock, info: mock.Mock) -> None:
|
||||||
mock_rmtree = mocker.patch("app.models.base.rmtree", autospec=True)
|
encoder = OpenClipTextualEncoder("ViT-B-32__openai", cache_dir=path)
|
||||||
mock_rmtree.avoids_symlink_attacks = True
|
|
||||||
mock_cache_dir = mocker.Mock()
|
|
||||||
mock_cache_dir.exists.return_value = True
|
|
||||||
mock_cache_dir.is_dir.return_value = True
|
|
||||||
mocker.patch("app.models.base.Path", return_value=mock_cache_dir)
|
|
||||||
info = mocker.spy(log, "info")
|
|
||||||
|
|
||||||
encoder = OpenClipTextualEncoder("ViT-B-32__openai", cache_dir=mock_cache_dir)
|
|
||||||
encoder.clear_cache()
|
encoder.clear_cache()
|
||||||
|
|
||||||
mock_rmtree.assert_called_once_with(encoder.cache_dir)
|
rmtree.assert_called_once_with(encoder.cache_dir)
|
||||||
info.assert_called_with(f"Cleared cache directory for model '{encoder.model_name}'.")
|
info.assert_called_with(f"Cleared cache directory for model '{encoder.model_name}'.")
|
||||||
|
|
||||||
def test_clear_cache_warns_if_path_does_not_exist(self, mocker: MockerFixture) -> None:
|
def test_clear_cache_warns_if_path_does_not_exist(
|
||||||
mock_rmtree = mocker.patch("app.models.base.rmtree", autospec=True)
|
self, rmtree: mock.Mock, path: mock.Mock, warning: mock.Mock
|
||||||
mock_rmtree.avoids_symlink_attacks = True
|
) -> None:
|
||||||
mock_cache_dir = mocker.Mock()
|
path.return_value.exists.return_value = False
|
||||||
mock_cache_dir.exists.return_value = False
|
|
||||||
mock_cache_dir.is_dir.return_value = True
|
|
||||||
mocker.patch("app.models.base.Path", return_value=mock_cache_dir)
|
|
||||||
warning = mocker.spy(log, "warning")
|
|
||||||
|
|
||||||
encoder = OpenClipTextualEncoder("ViT-B-32__openai", cache_dir=mock_cache_dir)
|
encoder = OpenClipTextualEncoder("ViT-B-32__openai", cache_dir=path)
|
||||||
encoder.clear_cache()
|
encoder.clear_cache()
|
||||||
|
|
||||||
mock_rmtree.assert_not_called()
|
rmtree.assert_not_called()
|
||||||
warning.assert_called_once()
|
warning.assert_called_once()
|
||||||
|
|
||||||
def test_clear_cache_raises_exception_if_vulnerable_to_symlink_attack(self, mocker: MockerFixture) -> None:
|
def test_clear_cache_raises_exception_if_vulnerable_to_symlink_attack(
|
||||||
mock_rmtree = mocker.patch("app.models.base.rmtree", autospec=True)
|
self, rmtree: mock.Mock, path: mock.Mock
|
||||||
mock_rmtree.avoids_symlink_attacks = False
|
) -> None:
|
||||||
mock_cache_dir = mocker.Mock()
|
rmtree.avoids_symlink_attacks = False
|
||||||
mock_cache_dir.exists.return_value = True
|
|
||||||
mock_cache_dir.is_dir.return_value = True
|
|
||||||
mocker.patch("app.models.base.Path", return_value=mock_cache_dir)
|
|
||||||
|
|
||||||
encoder = OpenClipTextualEncoder("ViT-B-32__openai", cache_dir=mock_cache_dir)
|
encoder = OpenClipTextualEncoder("ViT-B-32__openai", cache_dir=path)
|
||||||
with pytest.raises(RuntimeError):
|
with pytest.raises(RuntimeError):
|
||||||
encoder.clear_cache()
|
encoder.clear_cache()
|
||||||
|
|
||||||
mock_rmtree.assert_not_called()
|
rmtree.assert_not_called()
|
||||||
|
|
||||||
def test_clear_cache_replaces_file_with_dir_if_path_is_file(self, mocker: MockerFixture) -> None:
|
def test_clear_cache_replaces_file_with_dir_if_path_is_file(
|
||||||
mock_rmtree = mocker.patch("app.models.base.rmtree", autospec=True)
|
self, rmtree: mock.Mock, path: mock.Mock, warning: mock.Mock
|
||||||
mock_rmtree.avoids_symlink_attacks = True
|
) -> None:
|
||||||
mock_cache_dir = mocker.Mock()
|
path.return_value.is_dir.return_value = False
|
||||||
mock_cache_dir.exists.return_value = True
|
|
||||||
mock_cache_dir.is_dir.return_value = False
|
|
||||||
mocker.patch("app.models.base.Path", return_value=mock_cache_dir)
|
|
||||||
warning = mocker.spy(log, "warning")
|
|
||||||
|
|
||||||
encoder = OpenClipTextualEncoder("ViT-B-32__openai", cache_dir=mock_cache_dir)
|
encoder = OpenClipTextualEncoder("ViT-B-32__openai", cache_dir=path)
|
||||||
encoder.clear_cache()
|
encoder.clear_cache()
|
||||||
|
|
||||||
mock_rmtree.assert_not_called()
|
rmtree.assert_not_called()
|
||||||
mock_cache_dir.unlink.assert_called_once()
|
path.return_value.unlink.assert_called_once()
|
||||||
mock_cache_dir.mkdir.assert_called_once()
|
path.return_value.mkdir.assert_called_once()
|
||||||
warning.assert_called_once()
|
warning.assert_called_once()
|
||||||
|
|
||||||
def test_make_session_return_ann_if_available(self, mocker: MockerFixture) -> None:
|
def test_download(self, snapshot_download: mock.Mock) -> None:
|
||||||
mock_model_path = mocker.Mock()
|
|
||||||
mock_model_path.is_file.return_value = True
|
|
||||||
mock_model_path.suffix = ".armnn"
|
|
||||||
mock_model_path.with_suffix.return_value = mock_model_path
|
|
||||||
mock_ann = mocker.patch("app.models.base.AnnSession")
|
|
||||||
|
|
||||||
encoder = OpenClipTextualEncoder("ViT-B-32__openai")
|
|
||||||
encoder._make_session(mock_model_path)
|
|
||||||
|
|
||||||
mock_ann.assert_called_once()
|
|
||||||
|
|
||||||
def test_make_session_return_ort_if_available_and_ann_is_not(self, mocker: MockerFixture) -> None:
|
|
||||||
mock_armnn_path = mocker.Mock()
|
|
||||||
mock_armnn_path.is_file.return_value = False
|
|
||||||
mock_armnn_path.suffix = ".armnn"
|
|
||||||
|
|
||||||
mock_onnx_path = mocker.Mock()
|
|
||||||
mock_onnx_path.is_file.return_value = True
|
|
||||||
mock_onnx_path.suffix = ".onnx"
|
|
||||||
mock_armnn_path.with_suffix.return_value = mock_onnx_path
|
|
||||||
|
|
||||||
mock_ann = mocker.patch("app.models.base.AnnSession")
|
|
||||||
mock_ort = mocker.patch("app.models.base.ort.InferenceSession")
|
|
||||||
|
|
||||||
encoder = OpenClipTextualEncoder("ViT-B-32__openai")
|
|
||||||
encoder._make_session(mock_armnn_path)
|
|
||||||
|
|
||||||
mock_ort.assert_called_once()
|
|
||||||
mock_ann.assert_not_called()
|
|
||||||
|
|
||||||
def test_make_session_raises_exception_if_path_does_not_exist(self, mocker: MockerFixture) -> None:
|
|
||||||
mock_model_path = mocker.Mock()
|
|
||||||
mock_model_path.is_file.return_value = False
|
|
||||||
mock_model_path.suffix = ".onnx"
|
|
||||||
mock_model_path.with_suffix.return_value = mock_model_path
|
|
||||||
mock_ann = mocker.patch("app.models.base.AnnSession")
|
|
||||||
mock_ort = mocker.patch("app.models.base.ort.InferenceSession")
|
|
||||||
|
|
||||||
encoder = OpenClipTextualEncoder("ViT-B-32__openai")
|
|
||||||
with pytest.raises(ValueError):
|
|
||||||
encoder._make_session(mock_model_path)
|
|
||||||
|
|
||||||
mock_ann.assert_not_called()
|
|
||||||
mock_ort.assert_not_called()
|
|
||||||
|
|
||||||
def test_download(self, mocker: MockerFixture) -> None:
|
|
||||||
mock_snapshot_download = mocker.patch("app.models.base.snapshot_download")
|
|
||||||
|
|
||||||
encoder = OpenClipTextualEncoder("ViT-B-32__openai", cache_dir="/path/to/cache")
|
encoder = OpenClipTextualEncoder("ViT-B-32__openai", cache_dir="/path/to/cache")
|
||||||
encoder.download()
|
encoder.download()
|
||||||
|
|
||||||
mock_snapshot_download.assert_called_once_with(
|
snapshot_download.assert_called_once_with(
|
||||||
"immich-app/ViT-B-32__openai",
|
"immich-app/ViT-B-32__openai",
|
||||||
cache_dir=encoder.cache_dir,
|
cache_dir=encoder.cache_dir,
|
||||||
local_dir=encoder.cache_dir,
|
local_dir=encoder.cache_dir,
|
||||||
@@ -306,13 +128,11 @@ class TestBase:
|
|||||||
ignore_patterns=["*.armnn"],
|
ignore_patterns=["*.armnn"],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_download_downloads_armnn_if_preferred_format(self, mocker: MockerFixture) -> None:
|
def test_download_downloads_armnn_if_preferred_format(self, snapshot_download: mock.Mock) -> None:
|
||||||
mock_snapshot_download = mocker.patch("app.models.base.snapshot_download")
|
|
||||||
|
|
||||||
encoder = OpenClipTextualEncoder("ViT-B-32__openai", preferred_format=ModelFormat.ARMNN)
|
encoder = OpenClipTextualEncoder("ViT-B-32__openai", preferred_format=ModelFormat.ARMNN)
|
||||||
encoder.download()
|
encoder.download()
|
||||||
|
|
||||||
mock_snapshot_download.assert_called_once_with(
|
snapshot_download.assert_called_once_with(
|
||||||
"immich-app/ViT-B-32__openai",
|
"immich-app/ViT-B-32__openai",
|
||||||
cache_dir=encoder.cache_dir,
|
cache_dir=encoder.cache_dir,
|
||||||
local_dir=encoder.cache_dir,
|
local_dir=encoder.cache_dir,
|
||||||
@@ -321,6 +141,167 @@ class TestBase:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("ort_session")
|
||||||
|
class TestOrtSession:
|
||||||
|
CPU_EP = ["CPUExecutionProvider"]
|
||||||
|
CUDA_EP = ["CUDAExecutionProvider", "CPUExecutionProvider"]
|
||||||
|
OV_EP = ["OpenVINOExecutionProvider", "CPUExecutionProvider"]
|
||||||
|
CUDA_EP_OUT_OF_ORDER = ["CPUExecutionProvider", "CUDAExecutionProvider"]
|
||||||
|
TRT_EP = ["TensorrtExecutionProvider", "CUDAExecutionProvider", "CPUExecutionProvider"]
|
||||||
|
|
||||||
|
@pytest.mark.providers(CPU_EP)
|
||||||
|
def test_sets_cpu_provider(self, providers: list[str]) -> None:
|
||||||
|
session = OrtSession("ViT-B-32__openai")
|
||||||
|
|
||||||
|
assert session.providers == self.CPU_EP
|
||||||
|
|
||||||
|
@pytest.mark.providers(CUDA_EP)
|
||||||
|
def test_sets_cuda_provider_if_available(self, providers: list[str]) -> None:
|
||||||
|
session = OrtSession("ViT-B-32__openai")
|
||||||
|
|
||||||
|
assert session.providers == self.CUDA_EP
|
||||||
|
|
||||||
|
@pytest.mark.ov_device_ids(["GPU.0", "CPU"])
|
||||||
|
@pytest.mark.providers(OV_EP)
|
||||||
|
def test_sets_openvino_provider_if_available(self, providers: list[str], ov_device_ids: list[str]) -> None:
|
||||||
|
session = OrtSession("ViT-B-32__openai")
|
||||||
|
|
||||||
|
assert session.providers == self.OV_EP
|
||||||
|
|
||||||
|
@pytest.mark.ov_device_ids(["CPU"])
|
||||||
|
@pytest.mark.providers(OV_EP)
|
||||||
|
def test_avoids_openvino_if_gpu_not_available(self, providers: list[str], ov_device_ids: list[str]) -> None:
|
||||||
|
session = OrtSession("ViT-B-32__openai")
|
||||||
|
|
||||||
|
assert session.providers == self.CPU_EP
|
||||||
|
|
||||||
|
@pytest.mark.providers(CUDA_EP_OUT_OF_ORDER)
|
||||||
|
def test_sets_providers_in_correct_order(self, providers: list[str]) -> None:
|
||||||
|
session = OrtSession("ViT-B-32__openai")
|
||||||
|
|
||||||
|
assert session.providers == self.CUDA_EP
|
||||||
|
|
||||||
|
@pytest.mark.providers(TRT_EP)
|
||||||
|
def test_ignores_unsupported_providers(self, providers: list[str]) -> None:
|
||||||
|
session = OrtSession("ViT-B-32__openai")
|
||||||
|
|
||||||
|
assert session.providers == self.CUDA_EP
|
||||||
|
|
||||||
|
def test_sets_provider_kwarg(self) -> None:
|
||||||
|
providers = ["CUDAExecutionProvider"]
|
||||||
|
session = OrtSession("ViT-B-32__openai", providers=providers)
|
||||||
|
|
||||||
|
assert session.providers == providers
|
||||||
|
|
||||||
|
@pytest.mark.ov_device_ids(["GPU.0", "CPU"])
|
||||||
|
def test_sets_default_provider_options(self, ov_device_ids: list[str]) -> None:
|
||||||
|
model_path = "/cache/ViT-B-32__openai/model.onnx"
|
||||||
|
session = OrtSession(model_path, providers=["OpenVINOExecutionProvider", "CPUExecutionProvider"])
|
||||||
|
|
||||||
|
assert session.provider_options == [
|
||||||
|
{"device_type": "GPU_FP32", "cache_dir": "/cache/ViT-B-32__openai/openvino"},
|
||||||
|
{"arena_extend_strategy": "kSameAsRequested"},
|
||||||
|
]
|
||||||
|
|
||||||
|
def test_sets_provider_options_kwarg(self) -> None:
|
||||||
|
session = OrtSession(
|
||||||
|
"ViT-B-32__openai",
|
||||||
|
providers=["OpenVINOExecutionProvider", "CPUExecutionProvider"],
|
||||||
|
provider_options=[],
|
||||||
|
)
|
||||||
|
|
||||||
|
assert session.provider_options == []
|
||||||
|
|
||||||
|
def test_sets_default_sess_options(self) -> None:
|
||||||
|
session = OrtSession("ViT-B-32__openai")
|
||||||
|
|
||||||
|
assert session.sess_options.execution_mode == ort.ExecutionMode.ORT_SEQUENTIAL
|
||||||
|
assert session.sess_options.inter_op_num_threads == 1
|
||||||
|
assert session.sess_options.intra_op_num_threads == 2
|
||||||
|
assert session.sess_options.enable_cpu_mem_arena is False
|
||||||
|
|
||||||
|
def test_sets_default_sess_options_does_not_set_threads_if_non_cpu_and_default_threads(self) -> None:
|
||||||
|
session = OrtSession("ViT-B-32__openai", providers=["CUDAExecutionProvider", "CPUExecutionProvider"])
|
||||||
|
|
||||||
|
assert session.sess_options.inter_op_num_threads == 0
|
||||||
|
assert session.sess_options.intra_op_num_threads == 0
|
||||||
|
|
||||||
|
def test_sets_default_sess_options_sets_threads_if_non_cpu_and_set_threads(self, mocker: MockerFixture) -> None:
|
||||||
|
mock_settings = mocker.patch("app.sessions.ort.settings", autospec=True)
|
||||||
|
mock_settings.model_inter_op_threads = 2
|
||||||
|
mock_settings.model_intra_op_threads = 4
|
||||||
|
|
||||||
|
session = OrtSession("ViT-B-32__openai", providers=["CUDAExecutionProvider", "CPUExecutionProvider"])
|
||||||
|
|
||||||
|
assert session.sess_options.inter_op_num_threads == 2
|
||||||
|
assert session.sess_options.intra_op_num_threads == 4
|
||||||
|
|
||||||
|
def test_sets_sess_options_kwarg(self) -> None:
|
||||||
|
sess_options = ort.SessionOptions()
|
||||||
|
session = OrtSession(
|
||||||
|
"ViT-B-32__openai",
|
||||||
|
providers=["OpenVINOExecutionProvider", "CPUExecutionProvider"],
|
||||||
|
provider_options=[],
|
||||||
|
sess_options=sess_options,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert sess_options is session.sess_options
|
||||||
|
|
||||||
|
|
||||||
|
class TestAnnSession:
|
||||||
|
def test_creates_ann_session(self, ann_session: mock.Mock, info: mock.Mock) -> None:
|
||||||
|
model_path = mock.MagicMock(spec=Path)
|
||||||
|
cache_dir = mock.MagicMock(spec=Path)
|
||||||
|
|
||||||
|
AnnSession(model_path, cache_dir)
|
||||||
|
|
||||||
|
ann_session.assert_called_once_with(tuning_level=3, tuning_file=(cache_dir / "gpu-tuning.ann").as_posix())
|
||||||
|
ann_session.return_value.load.assert_called_once_with(
|
||||||
|
model_path.as_posix(), cached_network_path=model_path.with_suffix(".anncache").as_posix()
|
||||||
|
)
|
||||||
|
info.assert_has_calls(
|
||||||
|
[
|
||||||
|
mock.call("Loading ANN model %s ...", model_path),
|
||||||
|
mock.call("Loaded ANN model with ID %d", ann_session.return_value.load.return_value),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_get_inputs(self, ann_session: mock.Mock) -> None:
|
||||||
|
ann_session.return_value.load.return_value = 123
|
||||||
|
ann_session.return_value.input_shapes = {123: [(1, 3, 224, 224)]}
|
||||||
|
session = AnnSession(Path("ViT-B-32__openai"))
|
||||||
|
|
||||||
|
inputs = session.get_inputs()
|
||||||
|
|
||||||
|
assert len(inputs) == 1
|
||||||
|
assert inputs[0].name is None
|
||||||
|
assert inputs[0].shape == (1, 3, 224, 224)
|
||||||
|
|
||||||
|
def test_get_outputs(self, ann_session: mock.Mock) -> None:
|
||||||
|
ann_session.return_value.load.return_value = 123
|
||||||
|
ann_session.return_value.output_shapes = {123: [(1, 3, 224, 224)]}
|
||||||
|
session = AnnSession(Path("ViT-B-32__openai"))
|
||||||
|
|
||||||
|
outputs = session.get_outputs()
|
||||||
|
|
||||||
|
assert len(outputs) == 1
|
||||||
|
assert outputs[0].name is None
|
||||||
|
assert outputs[0].shape == (1, 3, 224, 224)
|
||||||
|
|
||||||
|
def test_run(self, ann_session: mock.Mock, mocker: MockerFixture) -> None:
|
||||||
|
ann_session.return_value.load.return_value = 123
|
||||||
|
np_spy = mocker.spy(np, "ascontiguousarray")
|
||||||
|
session = AnnSession(Path("ViT-B-32__openai"))
|
||||||
|
[input1, input2] = [np.random.rand(1, 3, 224, 224).astype(np.float32) for _ in range(2)]
|
||||||
|
input_feed = {"input.1": input1, "input.2": input2}
|
||||||
|
|
||||||
|
session.run(None, input_feed)
|
||||||
|
|
||||||
|
ann_session.return_value.execute.assert_called_once_with(123, [input1, input2])
|
||||||
|
np_spy.call_count == 2
|
||||||
|
np_spy.assert_has_calls([mock.call(input1), mock.call(input2)])
|
||||||
|
|
||||||
|
|
||||||
class TestCLIP:
|
class TestCLIP:
|
||||||
embedding = np.random.rand(512).astype(np.float32)
|
embedding = np.random.rand(512).astype(np.float32)
|
||||||
cache_dir = Path("test_cache")
|
cache_dir = Path("test_cache")
|
||||||
@@ -486,6 +467,59 @@ class TestFaceRecognition:
|
|||||||
assert isinstance(call_args[0][0], np.ndarray)
|
assert isinstance(call_args[0][0], np.ndarray)
|
||||||
assert call_args[0][0].shape == (112, 112, 3)
|
assert call_args[0][0].shape == (112, 112, 3)
|
||||||
|
|
||||||
|
def test_recognition_adds_batch_axis_for_ort(self, ort_session: mock.Mock, mocker: MockerFixture) -> None:
|
||||||
|
onnx = mocker.patch("app.models.facial_recognition.recognition.onnx", autospec=True)
|
||||||
|
update_dims = mocker.patch(
|
||||||
|
"app.models.facial_recognition.recognition.update_inputs_outputs_dims", autospec=True
|
||||||
|
)
|
||||||
|
mocker.patch("app.models.base.InferenceModel.download")
|
||||||
|
mocker.patch("app.models.facial_recognition.recognition.ArcFaceONNX")
|
||||||
|
|
||||||
|
ort_session.return_value.get_inputs.return_value = [SimpleNamespace(name="input.1", shape=(1, 3, 224, 224))]
|
||||||
|
ort_session.return_value.get_outputs.return_value = [SimpleNamespace(name="output.1", shape=(1, 800))]
|
||||||
|
|
||||||
|
proto = mock.Mock()
|
||||||
|
|
||||||
|
input_dims = mock.Mock()
|
||||||
|
input_dims.name = "input.1"
|
||||||
|
input_dims.type.tensor_type.shape.dim = [SimpleNamespace(dim_value=size) for size in [1, 3, 224, 224]]
|
||||||
|
proto.graph.input = [input_dims]
|
||||||
|
|
||||||
|
output_dims = mock.Mock()
|
||||||
|
output_dims.name = "output.1"
|
||||||
|
output_dims.type.tensor_type.shape.dim = [SimpleNamespace(dim_value=size) for size in [1, 800]]
|
||||||
|
proto.graph.output = [output_dims]
|
||||||
|
|
||||||
|
onnx.load.return_value = proto
|
||||||
|
|
||||||
|
face_recognizer = FaceRecognizer("buffalo_s")
|
||||||
|
face_recognizer.load()
|
||||||
|
|
||||||
|
assert face_recognizer.batch is True
|
||||||
|
update_dims.assert_called_once_with(proto, {"input.1": ["batch", 3, 224, 224]}, {"output.1": ["batch", 800]})
|
||||||
|
onnx.save.assert_called_once_with(update_dims.return_value, face_recognizer.model_path)
|
||||||
|
|
||||||
|
def test_recognition_does_not_add_batch_axis_if_exists(self, ort_session: mock.Mock, mocker: MockerFixture) -> None:
|
||||||
|
onnx = mocker.patch("app.models.facial_recognition.recognition.onnx", autospec=True)
|
||||||
|
update_dims = mocker.patch(
|
||||||
|
"app.models.facial_recognition.recognition.update_inputs_outputs_dims", autospec=True
|
||||||
|
)
|
||||||
|
mocker.patch("app.models.base.InferenceModel.download")
|
||||||
|
mocker.patch("app.models.facial_recognition.recognition.ArcFaceONNX")
|
||||||
|
|
||||||
|
inputs = [SimpleNamespace(name="input.1", shape=("batch", 3, 224, 224))]
|
||||||
|
outputs = [SimpleNamespace(name="output.1", shape=("batch", 800))]
|
||||||
|
ort_session.return_value.get_inputs.return_value = inputs
|
||||||
|
ort_session.return_value.get_outputs.return_value = outputs
|
||||||
|
|
||||||
|
face_recognizer = FaceRecognizer("buffalo_s")
|
||||||
|
face_recognizer.load()
|
||||||
|
|
||||||
|
assert face_recognizer.batch is True
|
||||||
|
update_dims.assert_not_called()
|
||||||
|
onnx.load.assert_not_called()
|
||||||
|
onnx.save.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
class TestCache:
|
class TestCache:
|
||||||
@@ -627,6 +661,7 @@ class TestLoad:
|
|||||||
async def test_load(self) -> None:
|
async def test_load(self) -> None:
|
||||||
mock_model = mock.Mock(spec=InferenceModel)
|
mock_model = mock.Mock(spec=InferenceModel)
|
||||||
mock_model.loaded = False
|
mock_model.loaded = False
|
||||||
|
mock_model.load_attempts = 0
|
||||||
|
|
||||||
res = await load(mock_model)
|
res = await load(mock_model)
|
||||||
|
|
||||||
@@ -650,6 +685,7 @@ class TestLoad:
|
|||||||
mock_model.model_task = ModelTask.SEARCH
|
mock_model.model_task = ModelTask.SEARCH
|
||||||
mock_model.load.side_effect = [OSError, None]
|
mock_model.load.side_effect = [OSError, None]
|
||||||
mock_model.loaded = False
|
mock_model.loaded = False
|
||||||
|
mock_model.load_attempts = 0
|
||||||
|
|
||||||
res = await load(mock_model)
|
res = await load(mock_model)
|
||||||
|
|
||||||
@@ -657,6 +693,20 @@ class TestLoad:
|
|||||||
mock_model.clear_cache.assert_called_once()
|
mock_model.clear_cache.assert_called_once()
|
||||||
assert mock_model.load.call_count == 2
|
assert mock_model.load.call_count == 2
|
||||||
|
|
||||||
|
async def test_load_clears_cache_and_raises_if_os_error_and_already_retried(self) -> None:
|
||||||
|
mock_model = mock.Mock(spec=InferenceModel)
|
||||||
|
mock_model.model_name = "test_model_name"
|
||||||
|
mock_model.model_type = ModelType.VISUAL
|
||||||
|
mock_model.model_task = ModelTask.SEARCH
|
||||||
|
mock_model.loaded = False
|
||||||
|
mock_model.load_attempts = 2
|
||||||
|
|
||||||
|
with pytest.raises(HTTPException):
|
||||||
|
await load(mock_model)
|
||||||
|
|
||||||
|
mock_model.clear_cache.assert_not_called()
|
||||||
|
mock_model.load.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
@pytest.mark.skipif(
|
||||||
not settings.test_full,
|
not settings.test_full,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM mambaorg/micromamba:bookworm-slim@sha256:4688551ffd61358d5bebfd88e0aac12d5b4aed7a153c170dbc435da453476a13 as builder
|
FROM mambaorg/micromamba:bookworm-slim@sha256:333f7598ff2c2400fb10bfe057709c68b7daab5d847143af85abcf224a07271a as builder
|
||||||
|
|
||||||
ENV TRANSFORMERS_CACHE=/cache \
|
ENV TRANSFORMERS_CACHE=/cache \
|
||||||
PYTHONDONTWRITEBYTECODE=1 \
|
PYTHONDONTWRITEBYTECODE=1 \
|
||||||
|
|||||||
261
machine-learning/poetry.lock
generated
261
machine-learning/poetry.lock
generated
@@ -1,4 +1,4 @@
|
|||||||
# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand.
|
# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aiocache"
|
name = "aiocache"
|
||||||
@@ -1236,13 +1236,13 @@ socks = ["socksio (==1.*)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "huggingface-hub"
|
name = "huggingface-hub"
|
||||||
version = "0.23.3"
|
version = "0.23.4"
|
||||||
description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub"
|
description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8.0"
|
python-versions = ">=3.8.0"
|
||||||
files = [
|
files = [
|
||||||
{file = "huggingface_hub-0.23.3-py3-none-any.whl", hash = "sha256:22222c41223f1b7c209ae5511d2d82907325a0e3cdbce5f66949d43c598ff3bc"},
|
{file = "huggingface_hub-0.23.4-py3-none-any.whl", hash = "sha256:3a0b957aa87150addf0cc7bd71b4d954b78e749850e1e7fb29ebbd2db64ca037"},
|
||||||
{file = "huggingface_hub-0.23.3.tar.gz", hash = "sha256:1a1118a0b3dea3bab6c325d71be16f5ffe441d32f3ac7c348d6875911b694b5b"},
|
{file = "huggingface_hub-0.23.4.tar.gz", hash = "sha256:35d99016433900e44ae7efe1c209164a5a81dbbcd53a52f99c281dcd7ce22431"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@@ -1530,13 +1530,13 @@ test = ["pytest (>=7.4)", "pytest-cov (>=4.1)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "locust"
|
name = "locust"
|
||||||
version = "2.28.0"
|
version = "2.29.0"
|
||||||
description = "Developer-friendly load testing framework"
|
description = "Developer-friendly load testing framework"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.9"
|
python-versions = ">=3.9"
|
||||||
files = [
|
files = [
|
||||||
{file = "locust-2.28.0-py3-none-any.whl", hash = "sha256:766be879db030c0118e7d9fca712f3538c4e628bdebf59468fa1c6c2fab217d3"},
|
{file = "locust-2.29.0-py3-none-any.whl", hash = "sha256:aa9d94d3604ed9f2aab3248460d91e55d3de980a821dffdf8658b439b049d03f"},
|
||||||
{file = "locust-2.28.0.tar.gz", hash = "sha256:260557eec866f7e34a767b6c916b5b278167562a280480aadb88f43d962fbdeb"},
|
{file = "locust-2.29.0.tar.gz", hash = "sha256:649c99ce49d00720a3084c0109547035ad9021222835386599a8b545d31ebe51"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@@ -1550,7 +1550,10 @@ msgpack = ">=1.0.0"
|
|||||||
psutil = ">=5.9.1"
|
psutil = ">=5.9.1"
|
||||||
pywin32 = {version = "*", markers = "platform_system == \"Windows\""}
|
pywin32 = {version = "*", markers = "platform_system == \"Windows\""}
|
||||||
pyzmq = ">=25.0.0"
|
pyzmq = ">=25.0.0"
|
||||||
requests = ">=2.26.0"
|
requests = [
|
||||||
|
{version = ">=2.32.2", markers = "python_version > \"3.11\""},
|
||||||
|
{version = ">=2.26.0", markers = "python_version <= \"3.11\""},
|
||||||
|
]
|
||||||
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
|
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
|
||||||
Werkzeug = ">=2.0.0"
|
Werkzeug = ">=2.0.0"
|
||||||
|
|
||||||
@@ -2054,80 +2057,81 @@ sympy = "*"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "opencv-python-headless"
|
name = "opencv-python-headless"
|
||||||
version = "4.10.0.82"
|
version = "4.10.0.84"
|
||||||
description = "Wrapper package for OpenCV python bindings."
|
description = "Wrapper package for OpenCV python bindings."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.6"
|
||||||
files = [
|
files = [
|
||||||
{file = "opencv-python-headless-4.10.0.82.tar.gz", hash = "sha256:de9e742c1b9540816fbd115b0b03841d41ed0c65566b0d7a5371f98b131b7e6d"},
|
{file = "opencv-python-headless-4.10.0.84.tar.gz", hash = "sha256:f2017c6101d7c2ef8d7bc3b414c37ff7f54d64413a1847d89970b6b7069b4e1a"},
|
||||||
{file = "opencv_python_headless-4.10.0.82-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:a09ed50ba21cc5bf5d436cb0e784ad09c692d6b1d1454252772f6c8f2c7b4088"},
|
{file = "opencv_python_headless-4.10.0.84-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:a4f4bcb07d8f8a7704d9c8564c224c8b064c63f430e95b61ac0bffaa374d330e"},
|
||||||
{file = "opencv_python_headless-4.10.0.82-cp37-abi3-macosx_12_0_x86_64.whl", hash = "sha256:977a5fd21e1fe0d3d2134887db4441f8725abeae95150126302f31fcd9f548fa"},
|
{file = "opencv_python_headless-4.10.0.84-cp37-abi3-macosx_12_0_x86_64.whl", hash = "sha256:5ae454ebac0eb0a0b932e3406370aaf4212e6a3fdb5038cc86c7aea15a6851da"},
|
||||||
{file = "opencv_python_headless-4.10.0.82-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db4ec6755838b0be12510bfc9ffb014779c612418f11f4f7e6f505c36124a3aa"},
|
{file = "opencv_python_headless-4.10.0.84-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46071015ff9ab40fccd8a163da0ee14ce9846349f06c6c8c0f2870856ffa45db"},
|
||||||
{file = "opencv_python_headless-4.10.0.82-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10a37fa5276967ecf6eb297295b16b28b7a2eb3b568ca0ee469fb1a5954de298"},
|
{file = "opencv_python_headless-4.10.0.84-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:377d08a7e48a1405b5e84afcbe4798464ce7ee17081c1c23619c8b398ff18295"},
|
||||||
{file = "opencv_python_headless-4.10.0.82-cp37-abi3-win32.whl", hash = "sha256:94736e9b322d13db4768fd35588ad5e8995e78e207263076bfbee18aac835ad5"},
|
{file = "opencv_python_headless-4.10.0.84-cp37-abi3-win32.whl", hash = "sha256:9092404b65458ed87ce932f613ffbb1106ed2c843577501e5768912360fc50ec"},
|
||||||
{file = "opencv_python_headless-4.10.0.82-cp37-abi3-win_amd64.whl", hash = "sha256:c1822fa23d1641c0249ed5eb906f4c385f7959ff1bd601a776d56b0c18914af4"},
|
{file = "opencv_python_headless-4.10.0.84-cp37-abi3-win_amd64.whl", hash = "sha256:afcf28bd1209dd58810d33defb622b325d3cbe49dcd7a43a902982c33e5fad05"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
numpy = [
|
numpy = [
|
||||||
{version = ">=1.23.5", markers = "python_version >= \"3.11\""},
|
{version = ">=1.26.0", markers = "python_version >= \"3.12\""},
|
||||||
|
{version = ">=1.23.5", markers = "python_version >= \"3.11\" and python_version < \"3.12\""},
|
||||||
{version = ">=1.21.4", markers = "python_version >= \"3.10\" and platform_system == \"Darwin\" and python_version < \"3.11\""},
|
{version = ">=1.21.4", markers = "python_version >= \"3.10\" and platform_system == \"Darwin\" and python_version < \"3.11\""},
|
||||||
{version = ">=1.21.2", markers = "platform_system != \"Darwin\" and python_version >= \"3.10\" and python_version < \"3.11\""},
|
{version = ">=1.21.2", markers = "platform_system != \"Darwin\" and python_version >= \"3.10\" and python_version < \"3.11\""},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "orjson"
|
name = "orjson"
|
||||||
version = "3.10.3"
|
version = "3.10.5"
|
||||||
description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy"
|
description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "orjson-3.10.3-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9fb6c3f9f5490a3eb4ddd46fc1b6eadb0d6fc16fb3f07320149c3286a1409dd8"},
|
{file = "orjson-3.10.5-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:545d493c1f560d5ccfc134803ceb8955a14c3fcb47bbb4b2fee0232646d0b932"},
|
||||||
{file = "orjson-3.10.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:252124b198662eee80428f1af8c63f7ff077c88723fe206a25df8dc57a57b1fa"},
|
{file = "orjson-3.10.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4324929c2dd917598212bfd554757feca3e5e0fa60da08be11b4aa8b90013c1"},
|
||||||
{file = "orjson-3.10.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9f3e87733823089a338ef9bbf363ef4de45e5c599a9bf50a7a9b82e86d0228da"},
|
{file = "orjson-3.10.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c13ca5e2ddded0ce6a927ea5a9f27cae77eee4c75547b4297252cb20c4d30e6"},
|
||||||
{file = "orjson-3.10.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c8334c0d87103bb9fbbe59b78129f1f40d1d1e8355bbed2ca71853af15fa4ed3"},
|
{file = "orjson-3.10.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b6c8e30adfa52c025f042a87f450a6b9ea29649d828e0fec4858ed5e6caecf63"},
|
||||||
{file = "orjson-3.10.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1952c03439e4dce23482ac846e7961f9d4ec62086eb98ae76d97bd41d72644d7"},
|
{file = "orjson-3.10.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:338fd4f071b242f26e9ca802f443edc588fa4ab60bfa81f38beaedf42eda226c"},
|
||||||
{file = "orjson-3.10.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c0403ed9c706dcd2809f1600ed18f4aae50be263bd7112e54b50e2c2bc3ebd6d"},
|
{file = "orjson-3.10.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6970ed7a3126cfed873c5d21ece1cd5d6f83ca6c9afb71bbae21a0b034588d96"},
|
||||||
{file = "orjson-3.10.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:382e52aa4270a037d41f325e7d1dfa395b7de0c367800b6f337d8157367bf3a7"},
|
{file = "orjson-3.10.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:235dadefb793ad12f7fa11e98a480db1f7c6469ff9e3da5e73c7809c700d746b"},
|
||||||
{file = "orjson-3.10.3-cp310-none-win32.whl", hash = "sha256:be2aab54313752c04f2cbaab4515291ef5af8c2256ce22abc007f89f42f49109"},
|
{file = "orjson-3.10.5-cp310-none-win32.whl", hash = "sha256:be79e2393679eda6a590638abda16d167754393f5d0850dcbca2d0c3735cebe2"},
|
||||||
{file = "orjson-3.10.3-cp310-none-win_amd64.whl", hash = "sha256:416b195f78ae461601893f482287cee1e3059ec49b4f99479aedf22a20b1098b"},
|
{file = "orjson-3.10.5-cp310-none-win_amd64.whl", hash = "sha256:c4a65310ccb5c9910c47b078ba78e2787cb3878cdded1702ac3d0da71ddc5228"},
|
||||||
{file = "orjson-3.10.3-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:73100d9abbbe730331f2242c1fc0bcb46a3ea3b4ae3348847e5a141265479700"},
|
{file = "orjson-3.10.5-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:cdf7365063e80899ae3a697def1277c17a7df7ccfc979990a403dfe77bb54d40"},
|
||||||
{file = "orjson-3.10.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:544a12eee96e3ab828dbfcb4d5a0023aa971b27143a1d35dc214c176fdfb29b3"},
|
{file = "orjson-3.10.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b68742c469745d0e6ca5724506858f75e2f1e5b59a4315861f9e2b1df77775a"},
|
||||||
{file = "orjson-3.10.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:520de5e2ef0b4ae546bea25129d6c7c74edb43fc6cf5213f511a927f2b28148b"},
|
{file = "orjson-3.10.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7d10cc1b594951522e35a3463da19e899abe6ca95f3c84c69e9e901e0bd93d38"},
|
||||||
{file = "orjson-3.10.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ccaa0a401fc02e8828a5bedfd80f8cd389d24f65e5ca3954d72c6582495b4bcf"},
|
{file = "orjson-3.10.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dcbe82b35d1ac43b0d84072408330fd3295c2896973112d495e7234f7e3da2e1"},
|
||||||
{file = "orjson-3.10.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a7bc9e8bc11bac40f905640acd41cbeaa87209e7e1f57ade386da658092dc16"},
|
{file = "orjson-3.10.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c0eb7e0c75e1e486c7563fe231b40fdd658a035ae125c6ba651ca3b07936f5"},
|
||||||
{file = "orjson-3.10.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3582b34b70543a1ed6944aca75e219e1192661a63da4d039d088a09c67543b08"},
|
{file = "orjson-3.10.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:53ed1c879b10de56f35daf06dbc4a0d9a5db98f6ee853c2dbd3ee9d13e6f302f"},
|
||||||
{file = "orjson-3.10.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1c23dfa91481de880890d17aa7b91d586a4746a4c2aa9a145bebdbaf233768d5"},
|
{file = "orjson-3.10.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:099e81a5975237fda3100f918839af95f42f981447ba8f47adb7b6a3cdb078fa"},
|
||||||
{file = "orjson-3.10.3-cp311-none-win32.whl", hash = "sha256:1770e2a0eae728b050705206d84eda8b074b65ee835e7f85c919f5705b006c9b"},
|
{file = "orjson-3.10.5-cp311-none-win32.whl", hash = "sha256:1146bf85ea37ac421594107195db8bc77104f74bc83e8ee21a2e58596bfb2f04"},
|
||||||
{file = "orjson-3.10.3-cp311-none-win_amd64.whl", hash = "sha256:93433b3c1f852660eb5abdc1f4dd0ced2be031ba30900433223b28ee0140cde5"},
|
{file = "orjson-3.10.5-cp311-none-win_amd64.whl", hash = "sha256:36a10f43c5f3a55c2f680efe07aa93ef4a342d2960dd2b1b7ea2dd764fe4a37c"},
|
||||||
{file = "orjson-3.10.3-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a39aa73e53bec8d410875683bfa3a8edf61e5a1c7bb4014f65f81d36467ea098"},
|
{file = "orjson-3.10.5-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:68f85ecae7af14a585a563ac741b0547a3f291de81cd1e20903e79f25170458f"},
|
||||||
{file = "orjson-3.10.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0943a96b3fa09bee1afdfccc2cb236c9c64715afa375b2af296c73d91c23eab2"},
|
{file = "orjson-3.10.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28afa96f496474ce60d3340fe8d9a263aa93ea01201cd2bad844c45cd21f5268"},
|
||||||
{file = "orjson-3.10.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e852baafceff8da3c9defae29414cc8513a1586ad93e45f27b89a639c68e8176"},
|
{file = "orjson-3.10.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cd684927af3e11b6e754df80b9ffafd9fb6adcaa9d3e8fdd5891be5a5cad51e"},
|
||||||
{file = "orjson-3.10.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18566beb5acd76f3769c1d1a7ec06cdb81edc4d55d2765fb677e3eaa10fa99e0"},
|
{file = "orjson-3.10.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d21b9983da032505f7050795e98b5d9eee0df903258951566ecc358f6696969"},
|
||||||
{file = "orjson-3.10.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bd2218d5a3aa43060efe649ec564ebedec8ce6ae0a43654b81376216d5ebd42"},
|
{file = "orjson-3.10.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ad1de7fef79736dde8c3554e75361ec351158a906d747bd901a52a5c9c8d24b"},
|
||||||
{file = "orjson-3.10.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:cf20465e74c6e17a104ecf01bf8cd3b7b252565b4ccee4548f18b012ff2f8069"},
|
{file = "orjson-3.10.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2d97531cdfe9bdd76d492e69800afd97e5930cb0da6a825646667b2c6c6c0211"},
|
||||||
{file = "orjson-3.10.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ba7f67aa7f983c4345eeda16054a4677289011a478ca947cd69c0a86ea45e534"},
|
{file = "orjson-3.10.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d69858c32f09c3e1ce44b617b3ebba1aba030e777000ebdf72b0d8e365d0b2b3"},
|
||||||
{file = "orjson-3.10.3-cp312-none-win32.whl", hash = "sha256:17e0713fc159abc261eea0f4feda611d32eabc35708b74bef6ad44f6c78d5ea0"},
|
{file = "orjson-3.10.5-cp312-none-win32.whl", hash = "sha256:64c9cc089f127e5875901ac05e5c25aa13cfa5dbbbd9602bda51e5c611d6e3e2"},
|
||||||
{file = "orjson-3.10.3-cp312-none-win_amd64.whl", hash = "sha256:4c895383b1ec42b017dd2c75ae8a5b862fc489006afde06f14afbdd0309b2af0"},
|
{file = "orjson-3.10.5-cp312-none-win_amd64.whl", hash = "sha256:b2efbd67feff8c1f7728937c0d7f6ca8c25ec81373dc8db4ef394c1d93d13dc5"},
|
||||||
{file = "orjson-3.10.3-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:be2719e5041e9fb76c8c2c06b9600fe8e8584e6980061ff88dcbc2691a16d20d"},
|
{file = "orjson-3.10.5-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:03b565c3b93f5d6e001db48b747d31ea3819b89abf041ee10ac6988886d18e01"},
|
||||||
{file = "orjson-3.10.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0175a5798bdc878956099f5c54b9837cb62cfbf5d0b86ba6d77e43861bcec2"},
|
{file = "orjson-3.10.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:584c902ec19ab7928fd5add1783c909094cc53f31ac7acfada817b0847975f26"},
|
||||||
{file = "orjson-3.10.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:978be58a68ade24f1af7758626806e13cff7748a677faf95fbb298359aa1e20d"},
|
{file = "orjson-3.10.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5a35455cc0b0b3a1eaf67224035f5388591ec72b9b6136d66b49a553ce9eb1e6"},
|
||||||
{file = "orjson-3.10.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16bda83b5c61586f6f788333d3cf3ed19015e3b9019188c56983b5a299210eb5"},
|
{file = "orjson-3.10.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1670fe88b116c2745a3a30b0f099b699a02bb3482c2591514baf5433819e4f4d"},
|
||||||
{file = "orjson-3.10.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ad1f26bea425041e0a1adad34630c4825a9e3adec49079b1fb6ac8d36f8b754"},
|
{file = "orjson-3.10.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:185c394ef45b18b9a7d8e8f333606e2e8194a50c6e3c664215aae8cf42c5385e"},
|
||||||
{file = "orjson-3.10.3-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:9e253498bee561fe85d6325ba55ff2ff08fb5e7184cd6a4d7754133bd19c9195"},
|
{file = "orjson-3.10.5-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:ca0b3a94ac8d3886c9581b9f9de3ce858263865fdaa383fbc31c310b9eac07c9"},
|
||||||
{file = "orjson-3.10.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0a62f9968bab8a676a164263e485f30a0b748255ee2f4ae49a0224be95f4532b"},
|
{file = "orjson-3.10.5-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:dfc91d4720d48e2a709e9c368d5125b4b5899dced34b5400c3837dadc7d6271b"},
|
||||||
{file = "orjson-3.10.3-cp38-none-win32.whl", hash = "sha256:8d0b84403d287d4bfa9bf7d1dc298d5c1c5d9f444f3737929a66f2fe4fb8f134"},
|
{file = "orjson-3.10.5-cp38-none-win32.whl", hash = "sha256:c05f16701ab2a4ca146d0bca950af254cb7c02f3c01fca8efbbad82d23b3d9d4"},
|
||||||
{file = "orjson-3.10.3-cp38-none-win_amd64.whl", hash = "sha256:8bc7a4df90da5d535e18157220d7915780d07198b54f4de0110eca6b6c11e290"},
|
{file = "orjson-3.10.5-cp38-none-win_amd64.whl", hash = "sha256:8a11d459338f96a9aa7f232ba95679fc0c7cedbd1b990d736467894210205c09"},
|
||||||
{file = "orjson-3.10.3-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9059d15c30e675a58fdcd6f95465c1522b8426e092de9fff20edebfdc15e1cb0"},
|
{file = "orjson-3.10.5-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:85c89131d7b3218db1b24c4abecea92fd6c7f9fab87441cfc342d3acc725d807"},
|
||||||
{file = "orjson-3.10.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d40c7f7938c9c2b934b297412c067936d0b54e4b8ab916fd1a9eb8f54c02294"},
|
{file = "orjson-3.10.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb66215277a230c456f9038d5e2d84778141643207f85336ef8d2a9da26bd7ca"},
|
||||||
{file = "orjson-3.10.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d4a654ec1de8fdaae1d80d55cee65893cb06494e124681ab335218be6a0691e7"},
|
{file = "orjson-3.10.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:51bbcdea96cdefa4a9b4461e690c75ad4e33796530d182bdd5c38980202c134a"},
|
||||||
{file = "orjson-3.10.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:831c6ef73f9aa53c5f40ae8f949ff7681b38eaddb6904aab89dca4d85099cb78"},
|
{file = "orjson-3.10.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbead71dbe65f959b7bd8cf91e0e11d5338033eba34c114f69078d59827ee139"},
|
||||||
{file = "orjson-3.10.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99b880d7e34542db89f48d14ddecbd26f06838b12427d5a25d71baceb5ba119d"},
|
{file = "orjson-3.10.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5df58d206e78c40da118a8c14fc189207fffdcb1f21b3b4c9c0c18e839b5a214"},
|
||||||
{file = "orjson-3.10.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2e5e176c994ce4bd434d7aafb9ecc893c15f347d3d2bbd8e7ce0b63071c52e25"},
|
{file = "orjson-3.10.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c4057c3b511bb8aef605616bd3f1f002a697c7e4da6adf095ca5b84c0fd43595"},
|
||||||
{file = "orjson-3.10.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b69a58a37dab856491bf2d3bbf259775fdce262b727f96aafbda359cb1d114d8"},
|
{file = "orjson-3.10.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b39e006b00c57125ab974362e740c14a0c6a66ff695bff44615dcf4a70ce2b86"},
|
||||||
{file = "orjson-3.10.3-cp39-none-win32.whl", hash = "sha256:b8d4d1a6868cde356f1402c8faeb50d62cee765a1f7ffcfd6de732ab0581e063"},
|
{file = "orjson-3.10.5-cp39-none-win32.whl", hash = "sha256:eded5138cc565a9d618e111c6d5c2547bbdd951114eb822f7f6309e04db0fb47"},
|
||||||
{file = "orjson-3.10.3-cp39-none-win_amd64.whl", hash = "sha256:5102f50c5fc46d94f2033fe00d392588564378260d64377aec702f21a7a22912"},
|
{file = "orjson-3.10.5-cp39-none-win_amd64.whl", hash = "sha256:cc28e90a7cae7fcba2493953cff61da5a52950e78dc2dacfe931a317ee3d8de7"},
|
||||||
{file = "orjson-3.10.3.tar.gz", hash = "sha256:2b166507acae7ba2f7c315dcf185a9111ad5e992ac81f2d507aac39193c2c818"},
|
{file = "orjson-3.10.5.tar.gz", hash = "sha256:7a5baef8a4284405d96c90c7c62b755e9ef1ada84c2406c24a9ebec86b89f46d"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2346,47 +2350,54 @@ files = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pydantic"
|
name = "pydantic"
|
||||||
version = "1.10.15"
|
version = "1.10.17"
|
||||||
description = "Data validation and settings management using python type hints"
|
description = "Data validation and settings management using python type hints"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
{file = "pydantic-1.10.15-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:22ed12ee588b1df028a2aa5d66f07bf8f8b4c8579c2e96d5a9c1f96b77f3bb55"},
|
{file = "pydantic-1.10.17-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0fa51175313cc30097660b10eec8ca55ed08bfa07acbfe02f7a42f6c242e9a4b"},
|
||||||
{file = "pydantic-1.10.15-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:75279d3cac98186b6ebc2597b06bcbc7244744f6b0b44a23e4ef01e5683cc0d2"},
|
{file = "pydantic-1.10.17-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c7e8988bb16988890c985bd2093df9dd731bfb9d5e0860db054c23034fab8f7a"},
|
||||||
{file = "pydantic-1.10.15-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50f1666a9940d3d68683c9d96e39640f709d7a72ff8702987dab1761036206bb"},
|
{file = "pydantic-1.10.17-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:371dcf1831f87c9e217e2b6a0c66842879a14873114ebb9d0861ab22e3b5bb1e"},
|
||||||
{file = "pydantic-1.10.15-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82790d4753ee5d00739d6cb5cf56bceb186d9d6ce134aca3ba7befb1eedbc2c8"},
|
{file = "pydantic-1.10.17-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4866a1579c0c3ca2c40575398a24d805d4db6cb353ee74df75ddeee3c657f9a7"},
|
||||||
{file = "pydantic-1.10.15-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:d207d5b87f6cbefbdb1198154292faee8017d7495a54ae58db06762004500d00"},
|
{file = "pydantic-1.10.17-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:543da3c6914795b37785703ffc74ba4d660418620cc273490d42c53949eeeca6"},
|
||||||
{file = "pydantic-1.10.15-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e49db944fad339b2ccb80128ffd3f8af076f9f287197a480bf1e4ca053a866f0"},
|
{file = "pydantic-1.10.17-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7623b59876f49e61c2e283551cc3647616d2fbdc0b4d36d3d638aae8547ea681"},
|
||||||
{file = "pydantic-1.10.15-cp310-cp310-win_amd64.whl", hash = "sha256:d3b5c4cbd0c9cb61bbbb19ce335e1f8ab87a811f6d589ed52b0254cf585d709c"},
|
{file = "pydantic-1.10.17-cp310-cp310-win_amd64.whl", hash = "sha256:409b2b36d7d7d19cd8310b97a4ce6b1755ef8bd45b9a2ec5ec2b124db0a0d8f3"},
|
||||||
{file = "pydantic-1.10.15-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c3d5731a120752248844676bf92f25a12f6e45425e63ce22e0849297a093b5b0"},
|
{file = "pydantic-1.10.17-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fa43f362b46741df8f201bf3e7dff3569fa92069bcc7b4a740dea3602e27ab7a"},
|
||||||
{file = "pydantic-1.10.15-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c365ad9c394f9eeffcb30a82f4246c0006417f03a7c0f8315d6211f25f7cb654"},
|
{file = "pydantic-1.10.17-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2a72d2a5ff86a3075ed81ca031eac86923d44bc5d42e719d585a8eb547bf0c9b"},
|
||||||
{file = "pydantic-1.10.15-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3287e1614393119c67bd4404f46e33ae3be3ed4cd10360b48d0a4459f420c6a3"},
|
{file = "pydantic-1.10.17-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4ad32aed3bf5eea5ca5decc3d1bbc3d0ec5d4fbcd72a03cdad849458decbc63"},
|
||||||
{file = "pydantic-1.10.15-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:be51dd2c8596b25fe43c0a4a59c2bee4f18d88efb8031188f9e7ddc6b469cf44"},
|
{file = "pydantic-1.10.17-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aeb4e741782e236ee7dc1fb11ad94dc56aabaf02d21df0e79e0c21fe07c95741"},
|
||||||
{file = "pydantic-1.10.15-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6a51a1dd4aa7b3f1317f65493a182d3cff708385327c1c82c81e4a9d6d65b2e4"},
|
{file = "pydantic-1.10.17-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d2f89a719411cb234105735a520b7c077158a81e0fe1cb05a79c01fc5eb59d3c"},
|
||||||
{file = "pydantic-1.10.15-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4e316e54b5775d1eb59187f9290aeb38acf620e10f7fd2f776d97bb788199e53"},
|
{file = "pydantic-1.10.17-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db3b48d9283d80a314f7a682f7acae8422386de659fffaba454b77a083c3937d"},
|
||||||
{file = "pydantic-1.10.15-cp311-cp311-win_amd64.whl", hash = "sha256:0d142fa1b8f2f0ae11ddd5e3e317dcac060b951d605fda26ca9b234b92214986"},
|
{file = "pydantic-1.10.17-cp311-cp311-win_amd64.whl", hash = "sha256:9c803a5113cfab7bbb912f75faa4fc1e4acff43e452c82560349fff64f852e1b"},
|
||||||
{file = "pydantic-1.10.15-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7ea210336b891f5ea334f8fc9f8f862b87acd5d4a0cbc9e3e208e7aa1775dabf"},
|
{file = "pydantic-1.10.17-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:820ae12a390c9cbb26bb44913c87fa2ff431a029a785642c1ff11fed0a095fcb"},
|
||||||
{file = "pydantic-1.10.15-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3453685ccd7140715e05f2193d64030101eaad26076fad4e246c1cc97e1bb30d"},
|
{file = "pydantic-1.10.17-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c1e51d1af306641b7d1574d6d3307eaa10a4991542ca324f0feb134fee259815"},
|
||||||
{file = "pydantic-1.10.15-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bea1f03b8d4e8e86702c918ccfd5d947ac268f0f0cc6ed71782e4b09353b26f"},
|
{file = "pydantic-1.10.17-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e53fb834aae96e7b0dadd6e92c66e7dd9cdf08965340ed04c16813102a47fab"},
|
||||||
{file = "pydantic-1.10.15-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:005655cabc29081de8243126e036f2065bd7ea5b9dff95fde6d2c642d39755de"},
|
{file = "pydantic-1.10.17-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e2495309b1266e81d259a570dd199916ff34f7f51f1b549a0d37a6d9b17b4dc"},
|
||||||
{file = "pydantic-1.10.15-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:af9850d98fc21e5bc24ea9e35dd80a29faf6462c608728a110c0a30b595e58b7"},
|
{file = "pydantic-1.10.17-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:098ad8de840c92ea586bf8efd9e2e90c6339d33ab5c1cfbb85be66e4ecf8213f"},
|
||||||
{file = "pydantic-1.10.15-cp37-cp37m-win_amd64.whl", hash = "sha256:d31ee5b14a82c9afe2bd26aaa405293d4237d0591527d9129ce36e58f19f95c1"},
|
{file = "pydantic-1.10.17-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:525bbef620dac93c430d5d6bdbc91bdb5521698d434adf4434a7ef6ffd5c4b7f"},
|
||||||
{file = "pydantic-1.10.15-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5e09c19df304b8123938dc3c53d3d3be6ec74b9d7d0d80f4f4b5432ae16c2022"},
|
{file = "pydantic-1.10.17-cp312-cp312-win_amd64.whl", hash = "sha256:6654028d1144df451e1da69a670083c27117d493f16cf83da81e1e50edce72ad"},
|
||||||
{file = "pydantic-1.10.15-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7ac9237cd62947db00a0d16acf2f3e00d1ae9d3bd602b9c415f93e7a9fc10528"},
|
{file = "pydantic-1.10.17-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c87cedb4680d1614f1d59d13fea353faf3afd41ba5c906a266f3f2e8c245d655"},
|
||||||
{file = "pydantic-1.10.15-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:584f2d4c98ffec420e02305cf675857bae03c9d617fcfdc34946b1160213a948"},
|
{file = "pydantic-1.10.17-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11289fa895bcbc8f18704efa1d8020bb9a86314da435348f59745473eb042e6b"},
|
||||||
{file = "pydantic-1.10.15-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bbc6989fad0c030bd70a0b6f626f98a862224bc2b1e36bfc531ea2facc0a340c"},
|
{file = "pydantic-1.10.17-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:94833612d6fd18b57c359a127cbfd932d9150c1b72fea7c86ab58c2a77edd7c7"},
|
||||||
{file = "pydantic-1.10.15-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d573082c6ef99336f2cb5b667b781d2f776d4af311574fb53d908517ba523c22"},
|
{file = "pydantic-1.10.17-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:d4ecb515fa7cb0e46e163ecd9d52f9147ba57bc3633dca0e586cdb7a232db9e3"},
|
||||||
{file = "pydantic-1.10.15-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6bd7030c9abc80134087d8b6e7aa957e43d35714daa116aced57269a445b8f7b"},
|
{file = "pydantic-1.10.17-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7017971ffa7fd7808146880aa41b266e06c1e6e12261768a28b8b41ba55c8076"},
|
||||||
{file = "pydantic-1.10.15-cp38-cp38-win_amd64.whl", hash = "sha256:3350f527bb04138f8aff932dc828f154847fbdc7a1a44c240fbfff1b57f49a12"},
|
{file = "pydantic-1.10.17-cp37-cp37m-win_amd64.whl", hash = "sha256:e840e6b2026920fc3f250ea8ebfdedf6ea7a25b77bf04c6576178e681942ae0f"},
|
||||||
{file = "pydantic-1.10.15-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:51d405b42f1b86703555797270e4970a9f9bd7953f3990142e69d1037f9d9e51"},
|
{file = "pydantic-1.10.17-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bfbb18b616abc4df70591b8c1ff1b3eabd234ddcddb86b7cac82657ab9017e33"},
|
||||||
{file = "pydantic-1.10.15-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a980a77c52723b0dc56640ced396b73a024d4b74f02bcb2d21dbbac1debbe9d0"},
|
{file = "pydantic-1.10.17-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ebb249096d873593e014535ab07145498957091aa6ae92759a32d40cb9998e2e"},
|
||||||
{file = "pydantic-1.10.15-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67f1a1fb467d3f49e1708a3f632b11c69fccb4e748a325d5a491ddc7b5d22383"},
|
{file = "pydantic-1.10.17-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8c209af63ccd7b22fba94b9024e8b7fd07feffee0001efae50dd99316b27768"},
|
||||||
{file = "pydantic-1.10.15-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:676ed48f2c5bbad835f1a8ed8a6d44c1cd5a21121116d2ac40bd1cd3619746ed"},
|
{file = "pydantic-1.10.17-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d4b40c9e13a0b61583e5599e7950490c700297b4a375b55b2b592774332798b7"},
|
||||||
{file = "pydantic-1.10.15-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:92229f73400b80c13afcd050687f4d7e88de9234d74b27e6728aa689abcf58cc"},
|
{file = "pydantic-1.10.17-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:c31d281c7485223caf6474fc2b7cf21456289dbaa31401844069b77160cab9c7"},
|
||||||
{file = "pydantic-1.10.15-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2746189100c646682eff0bce95efa7d2e203420d8e1c613dc0c6b4c1d9c1fde4"},
|
{file = "pydantic-1.10.17-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ae5184e99a060a5c80010a2d53c99aee76a3b0ad683d493e5f0620b5d86eeb75"},
|
||||||
{file = "pydantic-1.10.15-cp39-cp39-win_amd64.whl", hash = "sha256:394f08750bd8eaad714718812e7fab615f873b3cdd0b9d84e76e51ef3b50b6b7"},
|
{file = "pydantic-1.10.17-cp38-cp38-win_amd64.whl", hash = "sha256:ad1e33dc6b9787a6f0f3fd132859aa75626528b49cc1f9e429cdacb2608ad5f0"},
|
||||||
{file = "pydantic-1.10.15-py3-none-any.whl", hash = "sha256:28e552a060ba2740d0d2aabe35162652c1459a0b9069fe0db7f4ee0e18e74d58"},
|
{file = "pydantic-1.10.17-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7e17c0ee7192e54a10943f245dc79e36d9fe282418ea05b886e1c666063a7b54"},
|
||||||
{file = "pydantic-1.10.15.tar.gz", hash = "sha256:ca832e124eda231a60a041da4f013e3ff24949d94a01154b137fc2f2a43c3ffb"},
|
{file = "pydantic-1.10.17-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cafb9c938f61d1b182dfc7d44a7021326547b7b9cf695db5b68ec7b590214773"},
|
||||||
|
{file = "pydantic-1.10.17-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95ef534e3c22e5abbdbdd6f66b6ea9dac3ca3e34c5c632894f8625d13d084cbe"},
|
||||||
|
{file = "pydantic-1.10.17-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62d96b8799ae3d782df7ec9615cb59fc32c32e1ed6afa1b231b0595f6516e8ab"},
|
||||||
|
{file = "pydantic-1.10.17-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ab2f976336808fd5d539fdc26eb51f9aafc1f4b638e212ef6b6f05e753c8011d"},
|
||||||
|
{file = "pydantic-1.10.17-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b8ad363330557beac73159acfbeed220d5f1bfcd6b930302a987a375e02f74fd"},
|
||||||
|
{file = "pydantic-1.10.17-cp39-cp39-win_amd64.whl", hash = "sha256:48db882e48575ce4b39659558b2f9f37c25b8d348e37a2b4e32971dd5a7d6227"},
|
||||||
|
{file = "pydantic-1.10.17-py3-none-any.whl", hash = "sha256:e41b5b973e5c64f674b3b4720286ded184dcc26a691dd55f34391c62c6934688"},
|
||||||
|
{file = "pydantic-1.10.17.tar.gz", hash = "sha256:f434160fb14b353caf634149baaf847206406471ba70e64657c1e8330277a991"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@@ -2760,13 +2771,13 @@ typing-extensions = "*"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "requests"
|
name = "requests"
|
||||||
version = "2.31.0"
|
version = "2.32.3"
|
||||||
description = "Python HTTP for Humans."
|
description = "Python HTTP for Humans."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"},
|
{file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"},
|
||||||
{file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"},
|
{file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@@ -2799,28 +2810,28 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruff"
|
name = "ruff"
|
||||||
version = "0.4.8"
|
version = "0.4.10"
|
||||||
description = "An extremely fast Python linter and code formatter, written in Rust."
|
description = "An extremely fast Python linter and code formatter, written in Rust."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
{file = "ruff-0.4.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:7663a6d78f6adb0eab270fa9cf1ff2d28618ca3a652b60f2a234d92b9ec89066"},
|
{file = "ruff-0.4.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5c2c4d0859305ac5a16310eec40e4e9a9dec5dcdfbe92697acd99624e8638dac"},
|
||||||
{file = "ruff-0.4.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:eeceb78da8afb6de0ddada93112869852d04f1cd0f6b80fe464fd4e35c330913"},
|
{file = "ruff-0.4.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a79489607d1495685cdd911a323a35871abfb7a95d4f98fc6f85e799227ac46e"},
|
||||||
{file = "ruff-0.4.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aad360893e92486662ef3be0a339c5ca3c1b109e0134fcd37d534d4be9fb8de3"},
|
{file = "ruff-0.4.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1dd1681dfa90a41b8376a61af05cc4dc5ff32c8f14f5fe20dba9ff5deb80cd6"},
|
||||||
{file = "ruff-0.4.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:284c2e3f3396fb05f5f803c9fffb53ebbe09a3ebe7dda2929ed8d73ded736deb"},
|
{file = "ruff-0.4.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c75c53bb79d71310dc79fb69eb4902fba804a81f374bc86a9b117a8d077a1784"},
|
||||||
{file = "ruff-0.4.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7354f921e3fbe04d2a62d46707e569f9315e1a613307f7311a935743c51a764"},
|
{file = "ruff-0.4.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18238c80ee3d9100d3535d8eb15a59c4a0753b45cc55f8bf38f38d6a597b9739"},
|
||||||
{file = "ruff-0.4.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:72584676164e15a68a15778fd1b17c28a519e7a0622161eb2debdcdabdc71883"},
|
{file = "ruff-0.4.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d8f71885bce242da344989cae08e263de29752f094233f932d4f5cfb4ef36a81"},
|
||||||
{file = "ruff-0.4.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9678d5c9b43315f323af2233a04d747409d1e3aa6789620083a82d1066a35199"},
|
{file = "ruff-0.4.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:330421543bd3222cdfec481e8ff3460e8702ed1e58b494cf9d9e4bf90db52b9d"},
|
||||||
{file = "ruff-0.4.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704977a658131651a22b5ebeb28b717ef42ac6ee3b11e91dc87b633b5d83142b"},
|
{file = "ruff-0.4.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e9b6fb3a37b772628415b00c4fc892f97954275394ed611056a4b8a2631365e"},
|
||||||
{file = "ruff-0.4.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d05f8d6f0c3cce5026cecd83b7a143dcad503045857bc49662f736437380ad45"},
|
{file = "ruff-0.4.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f54c481b39a762d48f64d97351048e842861c6662d63ec599f67d515cb417f6"},
|
||||||
{file = "ruff-0.4.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6ea874950daca5697309d976c9afba830d3bf0ed66887481d6bca1673fc5b66a"},
|
{file = "ruff-0.4.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:67fe086b433b965c22de0b4259ddfe6fa541c95bf418499bedb9ad5fb8d1c631"},
|
||||||
{file = "ruff-0.4.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:fc95aac2943ddf360376be9aa3107c8cf9640083940a8c5bd824be692d2216dc"},
|
{file = "ruff-0.4.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:acfaaab59543382085f9eb51f8e87bac26bf96b164839955f244d07125a982ef"},
|
||||||
{file = "ruff-0.4.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:384154a1c3f4bf537bac69f33720957ee49ac8d484bfc91720cc94172026ceed"},
|
{file = "ruff-0.4.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:3cea07079962b2941244191569cf3a05541477286f5cafea638cd3aa94b56815"},
|
||||||
{file = "ruff-0.4.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e9d5ce97cacc99878aa0d084c626a15cd21e6b3d53fd6f9112b7fc485918e1fa"},
|
{file = "ruff-0.4.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:338a64ef0748f8c3a80d7f05785930f7965d71ca260904a9321d13be24b79695"},
|
||||||
{file = "ruff-0.4.8-py3-none-win32.whl", hash = "sha256:6d795d7639212c2dfd01991259460101c22aabf420d9b943f153ab9d9706e6a9"},
|
{file = "ruff-0.4.10-py3-none-win32.whl", hash = "sha256:ffe3cd2f89cb54561c62e5fa20e8f182c0a444934bf430515a4b422f1ab7b7ca"},
|
||||||
{file = "ruff-0.4.8-py3-none-win_amd64.whl", hash = "sha256:e14a3a095d07560a9d6769a72f781d73259655919d9b396c650fc98a8157555d"},
|
{file = "ruff-0.4.10-py3-none-win_amd64.whl", hash = "sha256:67f67cef43c55ffc8cc59e8e0b97e9e60b4837c8f21e8ab5ffd5d66e196e25f7"},
|
||||||
{file = "ruff-0.4.8-py3-none-win_arm64.whl", hash = "sha256:14019a06dbe29b608f6b7cbcec300e3170a8d86efaddb7b23405cb7f7dcaf780"},
|
{file = "ruff-0.4.10-py3-none-win_arm64.whl", hash = "sha256:dd1fcee327c20addac7916ca4e2653fbbf2e8388d8a6477ce5b4e986b68ae6c0"},
|
||||||
{file = "ruff-0.4.8.tar.gz", hash = "sha256:16d717b1d57b2e2fd68bd0bf80fb43931b79d05a7131aa477d66fc40fbd86268"},
|
{file = "ruff-0.4.10.tar.gz", hash = "sha256:3aa4f2bc388a30d346c56524f7cacca85945ba124945fe489952aadb6b5cd804"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3571,5 +3582,5 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"]
|
|||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = ">=3.10,<3.12"
|
python-versions = ">=3.10,<4.0"
|
||||||
content-hash = "db51ad1e631b569e106927683a13124252bd80974def1f2edbe23ac87d89c461"
|
content-hash = "df9afeda50e05cb62b322a047028a9b0851db197c4f379903c70adab3a98777a"
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "machine-learning"
|
name = "machine-learning"
|
||||||
version = "1.106.4"
|
version = "1.107.2"
|
||||||
description = ""
|
description = ""
|
||||||
authors = ["Hau Tran <alex.tran1502@gmail.com>"]
|
authors = ["Hau Tran <alex.tran1502@gmail.com>"]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
packages = [{include = "app"}]
|
packages = [{include = "app"}]
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = ">=3.10,<3.12"
|
python = ">=3.10,<4.0"
|
||||||
insightface = ">=0.7.3,<1.0"
|
insightface = ">=0.7.3,<1.0"
|
||||||
opencv-python-headless = ">=4.7.0.72,<5.0"
|
opencv-python-headless = ">=4.7.0.72,<5.0"
|
||||||
pillow = ">=9.5.0,<11.0"
|
pillow = ">=9.5.0,<11.0"
|
||||||
@@ -97,4 +97,4 @@ line-length = 120
|
|||||||
target-version = ['py311']
|
target-version = ['py311']
|
||||||
|
|
||||||
[tool.pytest.ini_options]
|
[tool.pytest.ini_options]
|
||||||
markers = ["providers"]
|
markers = ["providers", "ov_device_ids"]
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"flutter": "3.22.1"
|
"flutter": "3.22.2"
|
||||||
}
|
}
|
||||||
@@ -35,8 +35,8 @@ platform :android do
|
|||||||
task: 'bundle',
|
task: 'bundle',
|
||||||
build_type: 'Release',
|
build_type: 'Release',
|
||||||
properties: {
|
properties: {
|
||||||
"android.injected.version.code" => 144,
|
"android.injected.version.code" => 147,
|
||||||
"android.injected.version.name" => "1.106.4",
|
"android.injected.version.name" => "1.107.2",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab')
|
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab')
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<testsuites>
|
|
||||||
<testsuite name="fastlane.lanes">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000381">
|
|
||||||
|
|
||||||
</testcase>
|
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="1: bundleRelease" time="52.832426">
|
|
||||||
|
|
||||||
</testcase>
|
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="2: upload_to_play_store" time="27.616558">
|
|
||||||
|
|
||||||
</testcase>
|
|
||||||
|
|
||||||
</testsuite>
|
|
||||||
</testsuites>
|
|
||||||
@@ -9,6 +9,8 @@
|
|||||||
"advanced_settings_log_level_title": "Log level: {}",
|
"advanced_settings_log_level_title": "Log level: {}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "تكون بعض الأجهزة بطيئة للغاية في تحميل الصور المصغرة من الأصول الموجودة على الجهاز. قم بتنشيط هذا الإعداد لتحميل الصور البعيدة بدلاً من ذلك.",
|
"advanced_settings_prefer_remote_subtitle": "تكون بعض الأجهزة بطيئة للغاية في تحميل الصور المصغرة من الأصول الموجودة على الجهاز. قم بتنشيط هذا الإعداد لتحميل الصور البعيدة بدلاً من ذلك.",
|
||||||
"advanced_settings_prefer_remote_title": "تفضل الصور البعيدة",
|
"advanced_settings_prefer_remote_title": "تفضل الصور البعيدة",
|
||||||
|
"advanced_settings_proxy_headers_subtitle": "Define proxy headers Immich should send with each network request",
|
||||||
|
"advanced_settings_proxy_headers_title": "Proxy Headers",
|
||||||
"advanced_settings_self_signed_ssl_subtitle": "Skips SSL certificate verification for the server endpoint. Required for self-signed certificates.",
|
"advanced_settings_self_signed_ssl_subtitle": "Skips SSL certificate verification for the server endpoint. Required for self-signed certificates.",
|
||||||
"advanced_settings_self_signed_ssl_title": "السماح بشهادات SSL الموقعة ذاتيًا",
|
"advanced_settings_self_signed_ssl_title": "السماح بشهادات SSL الموقعة ذاتيًا",
|
||||||
"advanced_settings_tile_subtitle": "إعدادات المستخدم المتقدمة",
|
"advanced_settings_tile_subtitle": "إعدادات المستخدم المتقدمة",
|
||||||
@@ -203,6 +205,13 @@
|
|||||||
"favorites_page_title": "المفضلة",
|
"favorites_page_title": "المفضلة",
|
||||||
"haptic_feedback_switch": "تمكين ردود الفعل اللمسية",
|
"haptic_feedback_switch": "تمكين ردود الفعل اللمسية",
|
||||||
"haptic_feedback_title": "ردود فعل لمسية",
|
"haptic_feedback_title": "ردود فعل لمسية",
|
||||||
|
"header_settings_add_header_tip": "Add Header",
|
||||||
|
"header_settings_field_validator_msg": "Value cannot be empty",
|
||||||
|
"header_settings_header_name_input": "Header name",
|
||||||
|
"header_settings_header_value_input": "Header value",
|
||||||
|
"header_settings_page_title": "Proxy Headers",
|
||||||
|
"headers_settings_tile_subtitle": "Define proxy headers the app should send with each network request",
|
||||||
|
"headers_settings_tile_title": "Custom proxy headers",
|
||||||
"home_page_add_to_album_conflicts": "تمت إضافة {تمت إضافة} الأصول إلى الألبوم {الألبوم}.{فشل} الأصول موجودة بالفعل في الألبوم.",
|
"home_page_add_to_album_conflicts": "تمت إضافة {تمت إضافة} الأصول إلى الألبوم {الألبوم}.{فشل} الأصول موجودة بالفعل في الألبوم.",
|
||||||
"home_page_add_to_album_err_local": "لا يمكن إضافة الأصول المحلية إلى الألبومات حتى الآن ، سوف يتخطى",
|
"home_page_add_to_album_err_local": "لا يمكن إضافة الأصول المحلية إلى الألبومات حتى الآن ، سوف يتخطى",
|
||||||
"home_page_add_to_album_success": "تمت إضافة {تمت إضافة} الأصول إلى الألبوم {الألبوم}.",
|
"home_page_add_to_album_success": "تمت إضافة {تمت إضافة} الأصول إلى الألبوم {الألبوم}.",
|
||||||
@@ -295,6 +304,8 @@
|
|||||||
"memories_check_back_tomorrow": "التحقق مرة أخرى غدا لمزيد من الذكريات",
|
"memories_check_back_tomorrow": "التحقق مرة أخرى غدا لمزيد من الذكريات",
|
||||||
"memories_start_over": "ابدأ من جديد",
|
"memories_start_over": "ابدأ من جديد",
|
||||||
"memories_swipe_to_close": "اسحب لأعلى للإغلاق",
|
"memories_swipe_to_close": "اسحب لأعلى للإغلاق",
|
||||||
|
"memories_year_ago": "A year ago",
|
||||||
|
"memories_years_ago": "{} years ago",
|
||||||
"monthly_title_text_date_format": "ط ط ط",
|
"monthly_title_text_date_format": "ط ط ط",
|
||||||
"motion_photos_page_title": "الصور المتحركة",
|
"motion_photos_page_title": "الصور المتحركة",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "لا يمكن تعديل تاريخ الأصول (المواد) للقراءة فقط، سوف يتخطى",
|
"multiselect_grid_edit_date_time_err_read_only": "لا يمكن تعديل تاريخ الأصول (المواد) للقراءة فقط، سوف يتخطى",
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
"advanced_settings_log_level_title": "Úroveň protokolování: {}",
|
"advanced_settings_log_level_title": "Úroveň protokolování: {}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "U některých zařízení je načítání miniatur z prostředků v zařízení velmi pomalé. Aktivujte toto nastavení, aby se místo toho načítaly vzdálené obrázky.",
|
"advanced_settings_prefer_remote_subtitle": "U některých zařízení je načítání miniatur z prostředků v zařízení velmi pomalé. Aktivujte toto nastavení, aby se místo toho načítaly vzdálené obrázky.",
|
||||||
"advanced_settings_prefer_remote_title": "Preferovat vzdálené obrázky",
|
"advanced_settings_prefer_remote_title": "Preferovat vzdálené obrázky",
|
||||||
|
"advanced_settings_proxy_headers_subtitle": "Definice hlaviček proxy serveru, které by měl Immich odesílat s každým síťovým požadavkem",
|
||||||
|
"advanced_settings_proxy_headers_title": "Proxy hlavičky",
|
||||||
"advanced_settings_self_signed_ssl_subtitle": "Vynechá ověření SSL certifikátu serveru. Vyžadováno pro self-signed certifikáty.",
|
"advanced_settings_self_signed_ssl_subtitle": "Vynechá ověření SSL certifikátu serveru. Vyžadováno pro self-signed certifikáty.",
|
||||||
"advanced_settings_self_signed_ssl_title": "Povolit self-signed SSL certifikáty",
|
"advanced_settings_self_signed_ssl_title": "Povolit self-signed SSL certifikáty",
|
||||||
"advanced_settings_tile_subtitle": "Pokročilé uživatelské nastavení",
|
"advanced_settings_tile_subtitle": "Pokročilé uživatelské nastavení",
|
||||||
@@ -203,6 +205,13 @@
|
|||||||
"favorites_page_title": "Oblíbené",
|
"favorites_page_title": "Oblíbené",
|
||||||
"haptic_feedback_switch": "Povolit dotykovou zpětnou vazbu",
|
"haptic_feedback_switch": "Povolit dotykovou zpětnou vazbu",
|
||||||
"haptic_feedback_title": "Dotyková zpětná vazba",
|
"haptic_feedback_title": "Dotyková zpětná vazba",
|
||||||
|
"header_settings_add_header_tip": "Přidat hlavičku",
|
||||||
|
"header_settings_field_validator_msg": "Hodnota nemůže být prázdná",
|
||||||
|
"header_settings_header_name_input": "Název hlavičky",
|
||||||
|
"header_settings_header_value_input": "Hodnota hlavičky",
|
||||||
|
"header_settings_page_title": "Proxy hlavičky",
|
||||||
|
"headers_settings_tile_subtitle": "Definice hlaviček proxy serveru, které má aplikace odesílat s každým síťovým požadavkem",
|
||||||
|
"headers_settings_tile_title": "Vlastní proxy hlavičky",
|
||||||
"home_page_add_to_album_conflicts": "Přidáno {added} položek do alba {album}. {failed} položek je již v albu.",
|
"home_page_add_to_album_conflicts": "Přidáno {added} položek do alba {album}. {failed} položek je již v albu.",
|
||||||
"home_page_add_to_album_err_local": "Zatím není možné přidat lokální média do alb, přeskakuji",
|
"home_page_add_to_album_err_local": "Zatím není možné přidat lokální média do alb, přeskakuji",
|
||||||
"home_page_add_to_album_success": "Přidáno {added} položek do alba {album}.",
|
"home_page_add_to_album_success": "Přidáno {added} položek do alba {album}.",
|
||||||
@@ -295,6 +304,8 @@
|
|||||||
"memories_check_back_tomorrow": "Zítra se podívejte na další vzpomínky",
|
"memories_check_back_tomorrow": "Zítra se podívejte na další vzpomínky",
|
||||||
"memories_start_over": "Začít znovu",
|
"memories_start_over": "Začít znovu",
|
||||||
"memories_swipe_to_close": "Přejetím nahoru zavřete",
|
"memories_swipe_to_close": "Přejetím nahoru zavřete",
|
||||||
|
"memories_year_ago": "Před rokem",
|
||||||
|
"memories_years_ago": "Před {} roky",
|
||||||
"monthly_title_text_date_format": "LLLL y",
|
"monthly_title_text_date_format": "LLLL y",
|
||||||
"motion_photos_page_title": "Pohyblivé fotky",
|
"motion_photos_page_title": "Pohyblivé fotky",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "Nelze upravit datum položek pouze pro čtení, přeskakuji",
|
"multiselect_grid_edit_date_time_err_read_only": "Nelze upravit datum položek pouze pro čtení, přeskakuji",
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
"advanced_settings_log_level_title": "Logniveau: {}",
|
"advanced_settings_log_level_title": "Logniveau: {}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "Nogle enheder tager meget lang tid om at indlæse miniaturebilleder af elementer på enheden. Aktiver denne indstilling for i stedetat indlæse elementer fra serveren.",
|
"advanced_settings_prefer_remote_subtitle": "Nogle enheder tager meget lang tid om at indlæse miniaturebilleder af elementer på enheden. Aktiver denne indstilling for i stedetat indlæse elementer fra serveren.",
|
||||||
"advanced_settings_prefer_remote_title": "Foretræk elementer på serveren",
|
"advanced_settings_prefer_remote_title": "Foretræk elementer på serveren",
|
||||||
|
"advanced_settings_proxy_headers_subtitle": "Define proxy headers Immich should send with each network request",
|
||||||
|
"advanced_settings_proxy_headers_title": "Proxy Headers",
|
||||||
"advanced_settings_self_signed_ssl_subtitle": "Spring verificering af SSL-certifikat over for serverens endelokation. Kræves for selvsignerede certifikater.",
|
"advanced_settings_self_signed_ssl_subtitle": "Spring verificering af SSL-certifikat over for serverens endelokation. Kræves for selvsignerede certifikater.",
|
||||||
"advanced_settings_self_signed_ssl_title": "Tillad selvsignerede certifikater",
|
"advanced_settings_self_signed_ssl_title": "Tillad selvsignerede certifikater",
|
||||||
"advanced_settings_tile_subtitle": "Avancerede brugerindstillinger",
|
"advanced_settings_tile_subtitle": "Avancerede brugerindstillinger",
|
||||||
@@ -203,6 +205,13 @@
|
|||||||
"favorites_page_title": "Favoritter",
|
"favorites_page_title": "Favoritter",
|
||||||
"haptic_feedback_switch": "Slå haptisk feedback til",
|
"haptic_feedback_switch": "Slå haptisk feedback til",
|
||||||
"haptic_feedback_title": "Haptisk feedback",
|
"haptic_feedback_title": "Haptisk feedback",
|
||||||
|
"header_settings_add_header_tip": "Add Header",
|
||||||
|
"header_settings_field_validator_msg": "Value cannot be empty",
|
||||||
|
"header_settings_header_name_input": "Header name",
|
||||||
|
"header_settings_header_value_input": "Header value",
|
||||||
|
"header_settings_page_title": "Proxy Headers",
|
||||||
|
"headers_settings_tile_subtitle": "Define proxy headers the app should send with each network request",
|
||||||
|
"headers_settings_tile_title": "Custom proxy headers",
|
||||||
"home_page_add_to_album_conflicts": "Tilføjede {added} elementer til album {album}. {failed} elementer er allerede i albummet.",
|
"home_page_add_to_album_conflicts": "Tilføjede {added} elementer til album {album}. {failed} elementer er allerede i albummet.",
|
||||||
"home_page_add_to_album_err_local": "Kan endnu ikke tilføje lokale elementer til album. Springer over..",
|
"home_page_add_to_album_err_local": "Kan endnu ikke tilføje lokale elementer til album. Springer over..",
|
||||||
"home_page_add_to_album_success": "Tilføjede {added} elementer til album {album}.",
|
"home_page_add_to_album_success": "Tilføjede {added} elementer til album {album}.",
|
||||||
@@ -295,6 +304,8 @@
|
|||||||
"memories_check_back_tomorrow": "Kom tilbage i morgen for at se nye minder",
|
"memories_check_back_tomorrow": "Kom tilbage i morgen for at se nye minder",
|
||||||
"memories_start_over": "Start forfra",
|
"memories_start_over": "Start forfra",
|
||||||
"memories_swipe_to_close": "Stryg op for at lukke",
|
"memories_swipe_to_close": "Stryg op for at lukke",
|
||||||
|
"memories_year_ago": "A year ago",
|
||||||
|
"memories_years_ago": "{} years ago",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "Bevægelsesbilleder",
|
"motion_photos_page_title": "Bevægelsesbilleder",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "Kan ikke redigere datoen på kun læselige elementer. Springer over",
|
"multiselect_grid_edit_date_time_err_read_only": "Kan ikke redigere datoen på kun læselige elementer. Springer over",
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
"advanced_settings_log_level_title": "Log-Level: {}",
|
"advanced_settings_log_level_title": "Log-Level: {}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "Manche Endgeräte laden Vorschaubilder von lokalen Bilder sehr langsam. Durch diese Einstellung werden diese stattdessen direkt vom Server geladen.",
|
"advanced_settings_prefer_remote_subtitle": "Manche Endgeräte laden Vorschaubilder von lokalen Bilder sehr langsam. Durch diese Einstellung werden diese stattdessen direkt vom Server geladen.",
|
||||||
"advanced_settings_prefer_remote_title": "Server-Bilder bevorzugen",
|
"advanced_settings_prefer_remote_title": "Server-Bilder bevorzugen",
|
||||||
|
"advanced_settings_proxy_headers_subtitle": "Definiere Proxy-Header, die Immich bei jeder Netzwerkanfrage mitschicken soll",
|
||||||
|
"advanced_settings_proxy_headers_title": "Proxy-Headers",
|
||||||
"advanced_settings_self_signed_ssl_subtitle": "Verifizierung von SSL-Zertifikaten vom Server überspringen. Notwendig bei selbstsignierten Zertifikaten.",
|
"advanced_settings_self_signed_ssl_subtitle": "Verifizierung von SSL-Zertifikaten vom Server überspringen. Notwendig bei selbstsignierten Zertifikaten.",
|
||||||
"advanced_settings_self_signed_ssl_title": "Selbstsignierte SSL-Zertifikate erlauben",
|
"advanced_settings_self_signed_ssl_title": "Selbstsignierte SSL-Zertifikate erlauben",
|
||||||
"advanced_settings_tile_subtitle": "Erweiterte Benutzereinstellungen",
|
"advanced_settings_tile_subtitle": "Erweiterte Benutzereinstellungen",
|
||||||
@@ -52,14 +54,14 @@
|
|||||||
"asset_list_settings_title": "Fotogitter",
|
"asset_list_settings_title": "Fotogitter",
|
||||||
"asset_viewer_settings_title": "Fotoanzeige",
|
"asset_viewer_settings_title": "Fotoanzeige",
|
||||||
"backup_album_selection_page_albums_device": "Alben auf dem Gerät ({})",
|
"backup_album_selection_page_albums_device": "Alben auf dem Gerät ({})",
|
||||||
"backup_album_selection_page_albums_tap": "Einmalig tippen um das Album zu verwenden, doppelt tippen um es zu entfernen.",
|
"backup_album_selection_page_albums_tap": "Einmalig das Album antippen um es zu sichern, doppelt antippen um es nicht mehr zu sichern.",
|
||||||
"backup_album_selection_page_assets_scatter": "Elemente (Fotos / Videos) können sich über mehrere Alben verteilen. Daher können diese vor der Sicherung eingeschlossen oder ausgeschlossen werden.",
|
"backup_album_selection_page_assets_scatter": "Elemente (Fotos / Videos) können sich über mehrere Alben verteilen. Daher können diese vor der Sicherung eingeschlossen oder ausgeschlossen werden.",
|
||||||
"backup_album_selection_page_select_albums": "Alben auswählen",
|
"backup_album_selection_page_select_albums": "Alben auswählen",
|
||||||
"backup_album_selection_page_selection_info": "Information",
|
"backup_album_selection_page_selection_info": "Information",
|
||||||
"backup_album_selection_page_total_assets": "Elemente",
|
"backup_album_selection_page_total_assets": "Elemente",
|
||||||
"backup_all": "Alle",
|
"backup_all": "Alle",
|
||||||
"backup_background_service_backup_failed_message": "Fehler beim Sichern von Elementen. Probiere erneut...",
|
"backup_background_service_backup_failed_message": "Fehler beim Sichern von Elementen. Probiere erneut...",
|
||||||
"backup_background_service_connection_failed_message": "Es konnte keine Verbindung zum Server herstellen. Neuer Versuch...",
|
"backup_background_service_connection_failed_message": "Es konnte keine Verbindung zum Server hergestellt werden. Erneuter Versuch...",
|
||||||
"backup_background_service_current_upload_notification": "Lädt {} hoch",
|
"backup_background_service_current_upload_notification": "Lädt {} hoch",
|
||||||
"backup_background_service_default_notification": "Suche nach neuen Elementen…",
|
"backup_background_service_default_notification": "Suche nach neuen Elementen…",
|
||||||
"backup_background_service_error_title": "Fehler bei der Sicherung",
|
"backup_background_service_error_title": "Fehler bei der Sicherung",
|
||||||
@@ -103,7 +105,7 @@
|
|||||||
"backup_controller_page_status_on": "Sicherung im Vordergrund ist aktiv",
|
"backup_controller_page_status_on": "Sicherung im Vordergrund ist aktiv",
|
||||||
"backup_controller_page_storage_format": "{} von {} genutzt",
|
"backup_controller_page_storage_format": "{} von {} genutzt",
|
||||||
"backup_controller_page_to_backup": "Zu sichernde Alben",
|
"backup_controller_page_to_backup": "Zu sichernde Alben",
|
||||||
"backup_controller_page_total": "Gesamt",
|
"backup_controller_page_total": "Gesamtübersicht",
|
||||||
"backup_controller_page_total_sub": "Alle Fotos und Videos",
|
"backup_controller_page_total_sub": "Alle Fotos und Videos",
|
||||||
"backup_controller_page_turn_off": "Sicherung im Vordergrund ausschalten",
|
"backup_controller_page_turn_off": "Sicherung im Vordergrund ausschalten",
|
||||||
"backup_controller_page_turn_on": "Sicherung im Vordergrund einschalten",
|
"backup_controller_page_turn_on": "Sicherung im Vordergrund einschalten",
|
||||||
@@ -203,6 +205,13 @@
|
|||||||
"favorites_page_title": "Favoriten",
|
"favorites_page_title": "Favoriten",
|
||||||
"haptic_feedback_switch": "Haptisches Feedback aktivieren",
|
"haptic_feedback_switch": "Haptisches Feedback aktivieren",
|
||||||
"haptic_feedback_title": "Haptisches Feedback",
|
"haptic_feedback_title": "Haptisches Feedback",
|
||||||
|
"header_settings_add_header_tip": "Header hinzufügen",
|
||||||
|
"header_settings_field_validator_msg": "Der Wert darf nicht leer sein",
|
||||||
|
"header_settings_header_name_input": "Header-Name",
|
||||||
|
"header_settings_header_value_input": "Header-Wert",
|
||||||
|
"header_settings_page_title": "Proxy-Headers",
|
||||||
|
"headers_settings_tile_subtitle": "Definiere Proxy-Header, die die Anwendung bei jeder Netzwerkanfrage mitschicken soll",
|
||||||
|
"headers_settings_tile_title": "Benutzerdefinierte Proxy-Header",
|
||||||
"home_page_add_to_album_conflicts": "{added} Elemente zu {album} hinzugefügt. {failed} Elemente sind bereits vorhanden.",
|
"home_page_add_to_album_conflicts": "{added} Elemente zu {album} hinzugefügt. {failed} Elemente sind bereits vorhanden.",
|
||||||
"home_page_add_to_album_err_local": "Es können lokale Elemente noch nicht zu Alben hinzugefügt werden, überspringen...",
|
"home_page_add_to_album_err_local": "Es können lokale Elemente noch nicht zu Alben hinzugefügt werden, überspringen...",
|
||||||
"home_page_add_to_album_success": "{added} Elemente zu {album} hinzugefügt.",
|
"home_page_add_to_album_success": "{added} Elemente zu {album} hinzugefügt.",
|
||||||
@@ -295,6 +304,8 @@
|
|||||||
"memories_check_back_tomorrow": "Schau morgen wieder vorbei für weitere Erinnerungen!",
|
"memories_check_back_tomorrow": "Schau morgen wieder vorbei für weitere Erinnerungen!",
|
||||||
"memories_start_over": "Erneut beginnen",
|
"memories_start_over": "Erneut beginnen",
|
||||||
"memories_swipe_to_close": "Nach oben Wischen zum schließen",
|
"memories_swipe_to_close": "Nach oben Wischen zum schließen",
|
||||||
|
"memories_year_ago": "ein Jahr her",
|
||||||
|
"memories_years_ago": "{} Jahre her",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "Live-Fotos",
|
"motion_photos_page_title": "Live-Fotos",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "Das Datum und die Uhrzeit von schreibgeschützten Inhalten kann nicht verändert werden, überspringen...",
|
"multiselect_grid_edit_date_time_err_read_only": "Das Datum und die Uhrzeit von schreibgeschützten Inhalten kann nicht verändert werden, überspringen...",
|
||||||
@@ -502,7 +513,7 @@
|
|||||||
"trash_page_empty_trash_dialog_content": "Elemente im Papierkorb löschen? Diese Elemente werden dauerhaft aus Immich entfernt",
|
"trash_page_empty_trash_dialog_content": "Elemente im Papierkorb löschen? Diese Elemente werden dauerhaft aus Immich entfernt",
|
||||||
"trash_page_empty_trash_dialog_ok": "Ok",
|
"trash_page_empty_trash_dialog_ok": "Ok",
|
||||||
"trash_page_info": "Elemente im Papierkorb werden nach {} Tagen endgültig gelöscht.",
|
"trash_page_info": "Elemente im Papierkorb werden nach {} Tagen endgültig gelöscht.",
|
||||||
"trash_page_no_assets": "Keine Elemente im Papierkorb",
|
"trash_page_no_assets": "Es gibt keine Daten im Papierkorb",
|
||||||
"trash_page_restore": "Wiederherstellen",
|
"trash_page_restore": "Wiederherstellen",
|
||||||
"trash_page_restore_all": "Alle wiederherstellen",
|
"trash_page_restore_all": "Alle wiederherstellen",
|
||||||
"trash_page_select_assets_btn": "Elemente auswählen",
|
"trash_page_select_assets_btn": "Elemente auswählen",
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
"advanced_settings_log_level_title": "Επίπεδο καταγραφής: {}",
|
"advanced_settings_log_level_title": "Επίπεδο καταγραφής: {}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "Μερικές συσκευές αργούν πολύ να φορτώσουν μικρογραφίες από αρχεία στη συσκευή. Ενεργοποιήστε αυτήν τη ρύθμιση για να φορτώνονται αντί αυτού απομακρυσμένες εικόνες.",
|
"advanced_settings_prefer_remote_subtitle": "Μερικές συσκευές αργούν πολύ να φορτώσουν μικρογραφίες από αρχεία στη συσκευή. Ενεργοποιήστε αυτήν τη ρύθμιση για να φορτώνονται αντί αυτού απομακρυσμένες εικόνες.",
|
||||||
"advanced_settings_prefer_remote_title": "Προτίμηση απομακρυσμένων εικόνων.",
|
"advanced_settings_prefer_remote_title": "Προτίμηση απομακρυσμένων εικόνων.",
|
||||||
|
"advanced_settings_proxy_headers_subtitle": "Define proxy headers Immich should send with each network request",
|
||||||
|
"advanced_settings_proxy_headers_title": "Proxy Headers",
|
||||||
"advanced_settings_self_signed_ssl_subtitle": "Παρακάμπτει τον έλεγχο πιστοποιητικού SSL του διακομιστή. Απαραίτητο για αυτο-υπογεγραμμένα πιστοποιητικά.",
|
"advanced_settings_self_signed_ssl_subtitle": "Παρακάμπτει τον έλεγχο πιστοποιητικού SSL του διακομιστή. Απαραίτητο για αυτο-υπογεγραμμένα πιστοποιητικά.",
|
||||||
"advanced_settings_self_signed_ssl_title": "Να επιτρέπονται αυτο-υπογεγραμμένα πιστοποιητικά SSL",
|
"advanced_settings_self_signed_ssl_title": "Να επιτρέπονται αυτο-υπογεγραμμένα πιστοποιητικά SSL",
|
||||||
"advanced_settings_tile_subtitle": "Ρυθμίσεις προχωρημένου χρήστη",
|
"advanced_settings_tile_subtitle": "Ρυθμίσεις προχωρημένου χρήστη",
|
||||||
@@ -203,6 +205,13 @@
|
|||||||
"favorites_page_title": "Αγαπημένα",
|
"favorites_page_title": "Αγαπημένα",
|
||||||
"haptic_feedback_switch": "Enable haptic feedback",
|
"haptic_feedback_switch": "Enable haptic feedback",
|
||||||
"haptic_feedback_title": "Haptic Feedback",
|
"haptic_feedback_title": "Haptic Feedback",
|
||||||
|
"header_settings_add_header_tip": "Add Header",
|
||||||
|
"header_settings_field_validator_msg": "Value cannot be empty",
|
||||||
|
"header_settings_header_name_input": "Header name",
|
||||||
|
"header_settings_header_value_input": "Header value",
|
||||||
|
"header_settings_page_title": "Proxy Headers",
|
||||||
|
"headers_settings_tile_subtitle": "Define proxy headers the app should send with each network request",
|
||||||
|
"headers_settings_tile_title": "Custom proxy headers",
|
||||||
"home_page_add_to_album_conflicts": "Προστέθηκαν {added} στοιχεία στο άλμπουμ {album}. {failed} στοιχεία υπάρχουν ήδη στο άλμπουμ.",
|
"home_page_add_to_album_conflicts": "Προστέθηκαν {added} στοιχεία στο άλμπουμ {album}. {failed} στοιχεία υπάρχουν ήδη στο άλμπουμ.",
|
||||||
"home_page_add_to_album_err_local": "Δεν είναι ακόμη δυνατή η προσθήκη τοπικών στοιχείων σε άλμπουμ, παράβλεψη",
|
"home_page_add_to_album_err_local": "Δεν είναι ακόμη δυνατή η προσθήκη τοπικών στοιχείων σε άλμπουμ, παράβλεψη",
|
||||||
"home_page_add_to_album_success": "Προστέθηκαν {added} στοιχεία στο άλμπουμ {album}.",
|
"home_page_add_to_album_success": "Προστέθηκαν {added} στοιχεία στο άλμπουμ {album}.",
|
||||||
@@ -295,6 +304,8 @@
|
|||||||
"memories_check_back_tomorrow": "Check back tomorrow for more memories",
|
"memories_check_back_tomorrow": "Check back tomorrow for more memories",
|
||||||
"memories_start_over": "Start Over",
|
"memories_start_over": "Start Over",
|
||||||
"memories_swipe_to_close": "Swipe up to close",
|
"memories_swipe_to_close": "Swipe up to close",
|
||||||
|
"memories_year_ago": "A year ago",
|
||||||
|
"memories_years_ago": "{} years ago",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "Motion Photos",
|
"motion_photos_page_title": "Motion Photos",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
"advanced_settings_log_level_title": "Log level: {}",
|
"advanced_settings_log_level_title": "Log level: {}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "Some devices are painfully slow to load thumbnails from assets on the device. Activate this setting to load remote images instead.",
|
"advanced_settings_prefer_remote_subtitle": "Some devices are painfully slow to load thumbnails from assets on the device. Activate this setting to load remote images instead.",
|
||||||
"advanced_settings_prefer_remote_title": "Prefer remote images",
|
"advanced_settings_prefer_remote_title": "Prefer remote images",
|
||||||
|
"advanced_settings_proxy_headers_subtitle": "Define proxy headers Immich should send with each network request",
|
||||||
|
"advanced_settings_proxy_headers_title": "Proxy Headers",
|
||||||
"advanced_settings_self_signed_ssl_subtitle": "Skips SSL certificate verification for the server endpoint. Required for self-signed certificates.",
|
"advanced_settings_self_signed_ssl_subtitle": "Skips SSL certificate verification for the server endpoint. Required for self-signed certificates.",
|
||||||
"advanced_settings_self_signed_ssl_title": "Allow self-signed SSL certificates",
|
"advanced_settings_self_signed_ssl_title": "Allow self-signed SSL certificates",
|
||||||
"advanced_settings_tile_subtitle": "Advanced user's settings",
|
"advanced_settings_tile_subtitle": "Advanced user's settings",
|
||||||
@@ -203,6 +205,13 @@
|
|||||||
"favorites_page_title": "Favorites",
|
"favorites_page_title": "Favorites",
|
||||||
"haptic_feedback_switch": "Enable haptic feedback",
|
"haptic_feedback_switch": "Enable haptic feedback",
|
||||||
"haptic_feedback_title": "Haptic Feedback",
|
"haptic_feedback_title": "Haptic Feedback",
|
||||||
|
"header_settings_add_header_tip": "Add Header",
|
||||||
|
"header_settings_field_validator_msg": "Value cannot be empty",
|
||||||
|
"header_settings_header_name_input": "Header name",
|
||||||
|
"header_settings_header_value_input": "Header value",
|
||||||
|
"header_settings_page_title": "Proxy Headers",
|
||||||
|
"headers_settings_tile_subtitle": "Define proxy headers the app should send with each network request",
|
||||||
|
"headers_settings_tile_title": "Custom proxy headers",
|
||||||
"home_page_add_to_album_conflicts": "Added {added} assets to album {album}. {failed} assets are already in the album.",
|
"home_page_add_to_album_conflicts": "Added {added} assets to album {album}. {failed} assets are already in the album.",
|
||||||
"home_page_add_to_album_err_local": "Can not add local assets to albums yet, skipping",
|
"home_page_add_to_album_err_local": "Can not add local assets to albums yet, skipping",
|
||||||
"home_page_add_to_album_success": "Added {added} assets to album {album}.",
|
"home_page_add_to_album_success": "Added {added} assets to album {album}.",
|
||||||
@@ -295,6 +304,8 @@
|
|||||||
"memories_check_back_tomorrow": "Check back tomorrow for more memories",
|
"memories_check_back_tomorrow": "Check back tomorrow for more memories",
|
||||||
"memories_start_over": "Start Over",
|
"memories_start_over": "Start Over",
|
||||||
"memories_swipe_to_close": "Swipe up to close",
|
"memories_swipe_to_close": "Swipe up to close",
|
||||||
|
"memories_year_ago": "A year ago",
|
||||||
|
"memories_years_ago": "{} years ago",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "Motion Photos",
|
"motion_photos_page_title": "Motion Photos",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
"advanced_settings_log_level_title": "Nivel de registro: {}",
|
"advanced_settings_log_level_title": "Nivel de registro: {}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "Algunos dispositivos tardan mucho en cargar las miniaturas de los elementos encontrados en el dispositivo. Activa esta opción para cargar imágenes remotas en su lugar.",
|
"advanced_settings_prefer_remote_subtitle": "Algunos dispositivos tardan mucho en cargar las miniaturas de los elementos encontrados en el dispositivo. Activa esta opción para cargar imágenes remotas en su lugar.",
|
||||||
"advanced_settings_prefer_remote_title": "Preferir imágenes remotas",
|
"advanced_settings_prefer_remote_title": "Preferir imágenes remotas",
|
||||||
|
"advanced_settings_proxy_headers_subtitle": "Define proxy headers Immich should send with each network request",
|
||||||
|
"advanced_settings_proxy_headers_title": "Proxy Headers",
|
||||||
"advanced_settings_self_signed_ssl_subtitle": "Omitir verificación del certificado SSL del servidor. Requerido para certificados autofirmados",
|
"advanced_settings_self_signed_ssl_subtitle": "Omitir verificación del certificado SSL del servidor. Requerido para certificados autofirmados",
|
||||||
"advanced_settings_self_signed_ssl_title": "Permitir certificados autofirmados",
|
"advanced_settings_self_signed_ssl_title": "Permitir certificados autofirmados",
|
||||||
"advanced_settings_tile_subtitle": "Configuraciones avanzadas del usuario",
|
"advanced_settings_tile_subtitle": "Configuraciones avanzadas del usuario",
|
||||||
@@ -203,6 +205,13 @@
|
|||||||
"favorites_page_title": "Favoritos",
|
"favorites_page_title": "Favoritos",
|
||||||
"haptic_feedback_switch": "Activar respuesta háptica",
|
"haptic_feedback_switch": "Activar respuesta háptica",
|
||||||
"haptic_feedback_title": "Respuesta Háptica",
|
"haptic_feedback_title": "Respuesta Háptica",
|
||||||
|
"header_settings_add_header_tip": "Add Header",
|
||||||
|
"header_settings_field_validator_msg": "Value cannot be empty",
|
||||||
|
"header_settings_header_name_input": "Header name",
|
||||||
|
"header_settings_header_value_input": "Header value",
|
||||||
|
"header_settings_page_title": "Proxy Headers",
|
||||||
|
"headers_settings_tile_subtitle": "Define proxy headers the app should send with each network request",
|
||||||
|
"headers_settings_tile_title": "Custom proxy headers",
|
||||||
"home_page_add_to_album_conflicts": "{added} elementos agregados al álbum {album}.{failed} elementos ya existen en el álbum.",
|
"home_page_add_to_album_conflicts": "{added} elementos agregados al álbum {album}.{failed} elementos ya existen en el álbum.",
|
||||||
"home_page_add_to_album_err_local": "Aún no se pueden agregar elementos locales a álbumes, omitiendo",
|
"home_page_add_to_album_err_local": "Aún no se pueden agregar elementos locales a álbumes, omitiendo",
|
||||||
"home_page_add_to_album_success": "{added} elementos agregados al álbum {album}. ",
|
"home_page_add_to_album_success": "{added} elementos agregados al álbum {album}. ",
|
||||||
@@ -295,6 +304,8 @@
|
|||||||
"memories_check_back_tomorrow": "Vuelve mañana para más recuerdos",
|
"memories_check_back_tomorrow": "Vuelve mañana para más recuerdos",
|
||||||
"memories_start_over": "Empezar de nuevo",
|
"memories_start_over": "Empezar de nuevo",
|
||||||
"memories_swipe_to_close": "Desliza para cerrar",
|
"memories_swipe_to_close": "Desliza para cerrar",
|
||||||
|
"memories_year_ago": "A year ago",
|
||||||
|
"memories_years_ago": "{} years ago",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "Foto en Movimiento",
|
"motion_photos_page_title": "Foto en Movimiento",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "No se puede cambiar la fecha del archivo(s) de solo lectura, omitiendo",
|
"multiselect_grid_edit_date_time_err_read_only": "No se puede cambiar la fecha del archivo(s) de solo lectura, omitiendo",
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
"advanced_settings_log_level_title": "Log level: {}",
|
"advanced_settings_log_level_title": "Log level: {}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "Algunos dispositivos tardan mucho en cargar las miniaturas de recursos encontrados el dispositivo. Activa esta opción para cargar imágenes remotas en su lugar.",
|
"advanced_settings_prefer_remote_subtitle": "Algunos dispositivos tardan mucho en cargar las miniaturas de recursos encontrados el dispositivo. Activa esta opción para cargar imágenes remotas en su lugar.",
|
||||||
"advanced_settings_prefer_remote_title": "Preferir imágenes remotas",
|
"advanced_settings_prefer_remote_title": "Preferir imágenes remotas",
|
||||||
|
"advanced_settings_proxy_headers_subtitle": "Define proxy headers Immich should send with each network request",
|
||||||
|
"advanced_settings_proxy_headers_title": "Proxy Headers",
|
||||||
"advanced_settings_self_signed_ssl_subtitle": "Omitir verificación del certificado SSL del servidor. Requerido para certificados autofirmados",
|
"advanced_settings_self_signed_ssl_subtitle": "Omitir verificación del certificado SSL del servidor. Requerido para certificados autofirmados",
|
||||||
"advanced_settings_self_signed_ssl_title": "Permitir certificados autofirmados",
|
"advanced_settings_self_signed_ssl_title": "Permitir certificados autofirmados",
|
||||||
"advanced_settings_tile_subtitle": "Configuraciones avanzadas del usuario",
|
"advanced_settings_tile_subtitle": "Configuraciones avanzadas del usuario",
|
||||||
@@ -203,6 +205,13 @@
|
|||||||
"favorites_page_title": "Favoritos",
|
"favorites_page_title": "Favoritos",
|
||||||
"haptic_feedback_switch": "Enable haptic feedback",
|
"haptic_feedback_switch": "Enable haptic feedback",
|
||||||
"haptic_feedback_title": "Haptic Feedback",
|
"haptic_feedback_title": "Haptic Feedback",
|
||||||
|
"header_settings_add_header_tip": "Add Header",
|
||||||
|
"header_settings_field_validator_msg": "Value cannot be empty",
|
||||||
|
"header_settings_header_name_input": "Header name",
|
||||||
|
"header_settings_header_value_input": "Header value",
|
||||||
|
"header_settings_page_title": "Proxy Headers",
|
||||||
|
"headers_settings_tile_subtitle": "Define proxy headers the app should send with each network request",
|
||||||
|
"headers_settings_tile_title": "Custom proxy headers",
|
||||||
"home_page_add_to_album_conflicts": "{added} elementos agregados al álbum {album}.\n{failed} elementos ya existen en el álbum.",
|
"home_page_add_to_album_conflicts": "{added} elementos agregados al álbum {album}.\n{failed} elementos ya existen en el álbum.",
|
||||||
"home_page_add_to_album_err_local": "Aún no se pueden agregar recursos locales a álbumes, omitiendo",
|
"home_page_add_to_album_err_local": "Aún no se pueden agregar recursos locales a álbumes, omitiendo",
|
||||||
"home_page_add_to_album_success": "{added} elementos agregados al álbum {album}. ",
|
"home_page_add_to_album_success": "{added} elementos agregados al álbum {album}. ",
|
||||||
@@ -295,6 +304,8 @@
|
|||||||
"memories_check_back_tomorrow": "Check back tomorrow for more memories",
|
"memories_check_back_tomorrow": "Check back tomorrow for more memories",
|
||||||
"memories_start_over": "Start Over",
|
"memories_start_over": "Start Over",
|
||||||
"memories_swipe_to_close": "Swipe up to close",
|
"memories_swipe_to_close": "Swipe up to close",
|
||||||
|
"memories_year_ago": "A year ago",
|
||||||
|
"memories_years_ago": "{} years ago",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "Foto en Movimiento",
|
"motion_photos_page_title": "Foto en Movimiento",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
"advanced_settings_log_level_title": "Log level: {}",
|
"advanced_settings_log_level_title": "Log level: {}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "Algunos dispositivos tardan mucho en cargar las miniaturas de recursos encontrados el dispositivo. Activa esta opción para cargar imágenes remotas en su lugar.",
|
"advanced_settings_prefer_remote_subtitle": "Algunos dispositivos tardan mucho en cargar las miniaturas de recursos encontrados el dispositivo. Activa esta opción para cargar imágenes remotas en su lugar.",
|
||||||
"advanced_settings_prefer_remote_title": "Preferir imágenes remotas",
|
"advanced_settings_prefer_remote_title": "Preferir imágenes remotas",
|
||||||
|
"advanced_settings_proxy_headers_subtitle": "Define proxy headers Immich should send with each network request",
|
||||||
|
"advanced_settings_proxy_headers_title": "Proxy Headers",
|
||||||
"advanced_settings_self_signed_ssl_subtitle": "Omitir verificación del certificado SSL del servidor. Requerido para certificados autofirmados",
|
"advanced_settings_self_signed_ssl_subtitle": "Omitir verificación del certificado SSL del servidor. Requerido para certificados autofirmados",
|
||||||
"advanced_settings_self_signed_ssl_title": "Permitir certificados autofirmados",
|
"advanced_settings_self_signed_ssl_title": "Permitir certificados autofirmados",
|
||||||
"advanced_settings_tile_subtitle": "Configuraciones avanzadas del usuario",
|
"advanced_settings_tile_subtitle": "Configuraciones avanzadas del usuario",
|
||||||
@@ -203,6 +205,13 @@
|
|||||||
"favorites_page_title": "Favoritos",
|
"favorites_page_title": "Favoritos",
|
||||||
"haptic_feedback_switch": "Enable haptic feedback",
|
"haptic_feedback_switch": "Enable haptic feedback",
|
||||||
"haptic_feedback_title": "Haptic Feedback",
|
"haptic_feedback_title": "Haptic Feedback",
|
||||||
|
"header_settings_add_header_tip": "Add Header",
|
||||||
|
"header_settings_field_validator_msg": "Value cannot be empty",
|
||||||
|
"header_settings_header_name_input": "Header name",
|
||||||
|
"header_settings_header_value_input": "Header value",
|
||||||
|
"header_settings_page_title": "Proxy Headers",
|
||||||
|
"headers_settings_tile_subtitle": "Define proxy headers the app should send with each network request",
|
||||||
|
"headers_settings_tile_title": "Custom proxy headers",
|
||||||
"home_page_add_to_album_conflicts": "{added} elementos agregados al álbum {album}.\n{failed} elementos ya existen en el álbum.",
|
"home_page_add_to_album_conflicts": "{added} elementos agregados al álbum {album}.\n{failed} elementos ya existen en el álbum.",
|
||||||
"home_page_add_to_album_err_local": "Aún no se pueden agregar recursos locales a álbumes, omitiendo",
|
"home_page_add_to_album_err_local": "Aún no se pueden agregar recursos locales a álbumes, omitiendo",
|
||||||
"home_page_add_to_album_success": "{added} elementos agregados al álbum {album}. ",
|
"home_page_add_to_album_success": "{added} elementos agregados al álbum {album}. ",
|
||||||
@@ -295,6 +304,8 @@
|
|||||||
"memories_check_back_tomorrow": "Check back tomorrow for more memories",
|
"memories_check_back_tomorrow": "Check back tomorrow for more memories",
|
||||||
"memories_start_over": "Start Over",
|
"memories_start_over": "Start Over",
|
||||||
"memories_swipe_to_close": "Swipe up to close",
|
"memories_swipe_to_close": "Swipe up to close",
|
||||||
|
"memories_year_ago": "A year ago",
|
||||||
|
"memories_years_ago": "{} years ago",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "Foto en Movimiento",
|
"motion_photos_page_title": "Foto en Movimiento",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
"advanced_settings_log_level_title": "Log level: {}",
|
"advanced_settings_log_level_title": "Log level: {}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "Algunos dispositivos tardan mucho en cargar las miniaturas de recursos encontrados en el dispositivo. Activa esta opción para cargar imágenes remotas en su lugar.",
|
"advanced_settings_prefer_remote_subtitle": "Algunos dispositivos tardan mucho en cargar las miniaturas de recursos encontrados en el dispositivo. Activa esta opción para cargar imágenes remotas en su lugar.",
|
||||||
"advanced_settings_prefer_remote_title": "Preferir imágenes remotas",
|
"advanced_settings_prefer_remote_title": "Preferir imágenes remotas",
|
||||||
|
"advanced_settings_proxy_headers_subtitle": "Define proxy headers Immich should send with each network request",
|
||||||
|
"advanced_settings_proxy_headers_title": "Proxy Headers",
|
||||||
"advanced_settings_self_signed_ssl_subtitle": "Omite la verificación del certificado SSL para la URL del servidor. Requerido para certificados autofirmados.",
|
"advanced_settings_self_signed_ssl_subtitle": "Omite la verificación del certificado SSL para la URL del servidor. Requerido para certificados autofirmados.",
|
||||||
"advanced_settings_self_signed_ssl_title": "Permitir certificados SSL autofirmados",
|
"advanced_settings_self_signed_ssl_title": "Permitir certificados SSL autofirmados",
|
||||||
"advanced_settings_tile_subtitle": "Configuraciones avanzadas de usuario",
|
"advanced_settings_tile_subtitle": "Configuraciones avanzadas de usuario",
|
||||||
@@ -203,6 +205,13 @@
|
|||||||
"favorites_page_title": "Favoritos",
|
"favorites_page_title": "Favoritos",
|
||||||
"haptic_feedback_switch": "Enable haptic feedback",
|
"haptic_feedback_switch": "Enable haptic feedback",
|
||||||
"haptic_feedback_title": "Haptic Feedback",
|
"haptic_feedback_title": "Haptic Feedback",
|
||||||
|
"header_settings_add_header_tip": "Add Header",
|
||||||
|
"header_settings_field_validator_msg": "Value cannot be empty",
|
||||||
|
"header_settings_header_name_input": "Header name",
|
||||||
|
"header_settings_header_value_input": "Header value",
|
||||||
|
"header_settings_page_title": "Proxy Headers",
|
||||||
|
"headers_settings_tile_subtitle": "Define proxy headers the app should send with each network request",
|
||||||
|
"headers_settings_tile_title": "Custom proxy headers",
|
||||||
"home_page_add_to_album_conflicts": "{added} recursos agregados al álbum {album}.\n{failed} recursos ya existen en el álbum.",
|
"home_page_add_to_album_conflicts": "{added} recursos agregados al álbum {album}.\n{failed} recursos ya existen en el álbum.",
|
||||||
"home_page_add_to_album_err_local": "Aún no se pueden agregar recursos locales a álbumes, omitiendo",
|
"home_page_add_to_album_err_local": "Aún no se pueden agregar recursos locales a álbumes, omitiendo",
|
||||||
"home_page_add_to_album_success": "{added} recursos agregados al álbum {album}.",
|
"home_page_add_to_album_success": "{added} recursos agregados al álbum {album}.",
|
||||||
@@ -295,6 +304,8 @@
|
|||||||
"memories_check_back_tomorrow": "Check back tomorrow for more memories",
|
"memories_check_back_tomorrow": "Check back tomorrow for more memories",
|
||||||
"memories_start_over": "Start Over",
|
"memories_start_over": "Start Over",
|
||||||
"memories_swipe_to_close": "Swipe up to close",
|
"memories_swipe_to_close": "Swipe up to close",
|
||||||
|
"memories_year_ago": "A year ago",
|
||||||
|
"memories_years_ago": "{} years ago",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "Fotos en movimiento",
|
"motion_photos_page_title": "Fotos en movimiento",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
"advanced_settings_log_level_title": "Lokitaso: {}",
|
"advanced_settings_log_level_title": "Lokitaso: {}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "Jotkut laitteet ovat erittäin hitaita lataamaan esikatselukuvia laitteen kohteista. Aktivoi tämä asetus käyttääksesi etäkuvia.",
|
"advanced_settings_prefer_remote_subtitle": "Jotkut laitteet ovat erittäin hitaita lataamaan esikatselukuvia laitteen kohteista. Aktivoi tämä asetus käyttääksesi etäkuvia.",
|
||||||
"advanced_settings_prefer_remote_title": "Suosi etäkuvia",
|
"advanced_settings_prefer_remote_title": "Suosi etäkuvia",
|
||||||
|
"advanced_settings_proxy_headers_subtitle": "Define proxy headers Immich should send with each network request",
|
||||||
|
"advanced_settings_proxy_headers_title": "Proxy Headers",
|
||||||
"advanced_settings_self_signed_ssl_subtitle": "Ohita SSL sertifikaattivarmennus palvelimen päätepisteellä. Vaaditaan self-signed -sertifikaateissa.",
|
"advanced_settings_self_signed_ssl_subtitle": "Ohita SSL sertifikaattivarmennus palvelimen päätepisteellä. Vaaditaan self-signed -sertifikaateissa.",
|
||||||
"advanced_settings_self_signed_ssl_title": "Salli self-signed SSL -sertifikaatit",
|
"advanced_settings_self_signed_ssl_title": "Salli self-signed SSL -sertifikaatit",
|
||||||
"advanced_settings_tile_subtitle": "Edistyneen käyttäjän asetukset",
|
"advanced_settings_tile_subtitle": "Edistyneen käyttäjän asetukset",
|
||||||
@@ -203,6 +205,13 @@
|
|||||||
"favorites_page_title": "Suosikit",
|
"favorites_page_title": "Suosikit",
|
||||||
"haptic_feedback_switch": "Ota haptinen palaute käyttöön",
|
"haptic_feedback_switch": "Ota haptinen palaute käyttöön",
|
||||||
"haptic_feedback_title": "Haptinen palaute",
|
"haptic_feedback_title": "Haptinen palaute",
|
||||||
|
"header_settings_add_header_tip": "Add Header",
|
||||||
|
"header_settings_field_validator_msg": "Value cannot be empty",
|
||||||
|
"header_settings_header_name_input": "Header name",
|
||||||
|
"header_settings_header_value_input": "Header value",
|
||||||
|
"header_settings_page_title": "Proxy Headers",
|
||||||
|
"headers_settings_tile_subtitle": "Define proxy headers the app should send with each network request",
|
||||||
|
"headers_settings_tile_title": "Custom proxy headers",
|
||||||
"home_page_add_to_album_conflicts": "Lisätty {added} kohdetta albumiin {album}. {failed} kohdetta on jo albumissa.",
|
"home_page_add_to_album_conflicts": "Lisätty {added} kohdetta albumiin {album}. {failed} kohdetta on jo albumissa.",
|
||||||
"home_page_add_to_album_err_local": "Paikallisten kohteiden lisääminen albumeihin ei ole mahdollista, ohitetaan",
|
"home_page_add_to_album_err_local": "Paikallisten kohteiden lisääminen albumeihin ei ole mahdollista, ohitetaan",
|
||||||
"home_page_add_to_album_success": "Lisätty {added} kohdetta albumiin {album}.",
|
"home_page_add_to_album_success": "Lisätty {added} kohdetta albumiin {album}.",
|
||||||
@@ -295,6 +304,8 @@
|
|||||||
"memories_check_back_tomorrow": "Palaa huomenna nähdäskesi lisää muistoja",
|
"memories_check_back_tomorrow": "Palaa huomenna nähdäskesi lisää muistoja",
|
||||||
"memories_start_over": "Aloita alusta",
|
"memories_start_over": "Aloita alusta",
|
||||||
"memories_swipe_to_close": "Pyyhkäise ylös sulkeaksesi",
|
"memories_swipe_to_close": "Pyyhkäise ylös sulkeaksesi",
|
||||||
|
"memories_year_ago": "A year ago",
|
||||||
|
"memories_years_ago": "{} years ago",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "Liikekuvat",
|
"motion_photos_page_title": "Liikekuvat",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "Vain luku -tilassa olevien kohteiden päivämäärää ei voitu muokata, ohitetaan",
|
"multiselect_grid_edit_date_time_err_read_only": "Vain luku -tilassa olevien kohteiden päivämäärää ei voitu muokata, ohitetaan",
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
"advanced_settings_log_level_title": "Log level: {}",
|
"advanced_settings_log_level_title": "Log level: {}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "Certains appareils sont très lents à charger des vignettes à partir de ressources présentes sur l'appareil. Activez ce paramètre pour charger des images externes à la place.",
|
"advanced_settings_prefer_remote_subtitle": "Certains appareils sont très lents à charger des vignettes à partir de ressources présentes sur l'appareil. Activez ce paramètre pour charger des images externes à la place.",
|
||||||
"advanced_settings_prefer_remote_title": "Préférer les images externes",
|
"advanced_settings_prefer_remote_title": "Préférer les images externes",
|
||||||
|
"advanced_settings_proxy_headers_subtitle": "Define proxy headers Immich should send with each network request",
|
||||||
|
"advanced_settings_proxy_headers_title": "Proxy Headers",
|
||||||
"advanced_settings_self_signed_ssl_subtitle": "Permet d'ignorer la vérification du certificat SSL pour le point d'accès du serveur. Requis pour les certificats auto-signés.",
|
"advanced_settings_self_signed_ssl_subtitle": "Permet d'ignorer la vérification du certificat SSL pour le point d'accès du serveur. Requis pour les certificats auto-signés.",
|
||||||
"advanced_settings_self_signed_ssl_title": "Autoriser les certificats SSL auto-signés",
|
"advanced_settings_self_signed_ssl_title": "Autoriser les certificats SSL auto-signés",
|
||||||
"advanced_settings_tile_subtitle": "Paramètres d'utilisateur avancés",
|
"advanced_settings_tile_subtitle": "Paramètres d'utilisateur avancés",
|
||||||
@@ -203,6 +205,13 @@
|
|||||||
"favorites_page_title": "Favoris",
|
"favorites_page_title": "Favoris",
|
||||||
"haptic_feedback_switch": "Enable haptic feedback",
|
"haptic_feedback_switch": "Enable haptic feedback",
|
||||||
"haptic_feedback_title": "Haptic Feedback",
|
"haptic_feedback_title": "Haptic Feedback",
|
||||||
|
"header_settings_add_header_tip": "Add Header",
|
||||||
|
"header_settings_field_validator_msg": "Value cannot be empty",
|
||||||
|
"header_settings_header_name_input": "Header name",
|
||||||
|
"header_settings_header_value_input": "Header value",
|
||||||
|
"header_settings_page_title": "Proxy Headers",
|
||||||
|
"headers_settings_tile_subtitle": "Define proxy headers the app should send with each network request",
|
||||||
|
"headers_settings_tile_title": "Custom proxy headers",
|
||||||
"home_page_add_to_album_conflicts": "{added} éléments ajoutés à l'album {album}. Les éléments {failed} sont déjà dans l'album.",
|
"home_page_add_to_album_conflicts": "{added} éléments ajoutés à l'album {album}. Les éléments {failed} sont déjà dans l'album.",
|
||||||
"home_page_add_to_album_err_local": "Impossible d'ajouter des éléments locaux aux albums pour le moment, étape ignorée",
|
"home_page_add_to_album_err_local": "Impossible d'ajouter des éléments locaux aux albums pour le moment, étape ignorée",
|
||||||
"home_page_add_to_album_success": "{added} éléments ajoutés à l'album {album}.",
|
"home_page_add_to_album_success": "{added} éléments ajoutés à l'album {album}.",
|
||||||
@@ -295,6 +304,8 @@
|
|||||||
"memories_check_back_tomorrow": "Check back tomorrow for more memories",
|
"memories_check_back_tomorrow": "Check back tomorrow for more memories",
|
||||||
"memories_start_over": "Start Over",
|
"memories_start_over": "Start Over",
|
||||||
"memories_swipe_to_close": "Swipe up to close",
|
"memories_swipe_to_close": "Swipe up to close",
|
||||||
|
"memories_year_ago": "A year ago",
|
||||||
|
"memories_years_ago": "{} years ago",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "Photos avec mouvement",
|
"motion_photos_page_title": "Photos avec mouvement",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
"advanced_settings_log_level_title": "Log level: {}",
|
"advanced_settings_log_level_title": "Log level: {}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "Certains appareils sont terriblement lents à charger des miniatures à partir de ressources présentes sur l'appareil. Activez ce paramètre pour charger des images distantes à la place.",
|
"advanced_settings_prefer_remote_subtitle": "Certains appareils sont terriblement lents à charger des miniatures à partir de ressources présentes sur l'appareil. Activez ce paramètre pour charger des images distantes à la place.",
|
||||||
"advanced_settings_prefer_remote_title": "Préférer les images distantes",
|
"advanced_settings_prefer_remote_title": "Préférer les images distantes",
|
||||||
|
"advanced_settings_proxy_headers_subtitle": "Define proxy headers Immich should send with each network request",
|
||||||
|
"advanced_settings_proxy_headers_title": "Proxy Headers",
|
||||||
"advanced_settings_self_signed_ssl_subtitle": "Permet d'ignorer la vérification du certificat SSL pour le point d'extrémité du serveur. Requis pour les certificats auto-signés.",
|
"advanced_settings_self_signed_ssl_subtitle": "Permet d'ignorer la vérification du certificat SSL pour le point d'extrémité du serveur. Requis pour les certificats auto-signés.",
|
||||||
"advanced_settings_self_signed_ssl_title": "Autoriser les certificats SSL auto-signés",
|
"advanced_settings_self_signed_ssl_title": "Autoriser les certificats SSL auto-signés",
|
||||||
"advanced_settings_tile_subtitle": "Paramètres d'utilisateur avancés",
|
"advanced_settings_tile_subtitle": "Paramètres d'utilisateur avancés",
|
||||||
@@ -203,6 +205,13 @@
|
|||||||
"favorites_page_title": "Favoris",
|
"favorites_page_title": "Favoris",
|
||||||
"haptic_feedback_switch": "Activer le retour haptique",
|
"haptic_feedback_switch": "Activer le retour haptique",
|
||||||
"haptic_feedback_title": "Retour haptique",
|
"haptic_feedback_title": "Retour haptique",
|
||||||
|
"header_settings_add_header_tip": "Add Header",
|
||||||
|
"header_settings_field_validator_msg": "Value cannot be empty",
|
||||||
|
"header_settings_header_name_input": "Nom de l'en-tête",
|
||||||
|
"header_settings_header_value_input": "Valeur de l'en-tête",
|
||||||
|
"header_settings_page_title": "En-têtes de proxy",
|
||||||
|
"headers_settings_tile_subtitle": "Définir les en-têtes de proxy que l'application doit envoyer avec chaque requête réseau",
|
||||||
|
"headers_settings_tile_title": "En-têtes de proxy personnalisés",
|
||||||
"home_page_add_to_album_conflicts": "{added} éléments ajoutés à l'album {album}. Les éléments {failed} sont déjà dans l'album.",
|
"home_page_add_to_album_conflicts": "{added} éléments ajoutés à l'album {album}. Les éléments {failed} sont déjà dans l'album.",
|
||||||
"home_page_add_to_album_err_local": "Impossible d'ajouter des éléments locaux aux albums pour le moment, étape ignorée",
|
"home_page_add_to_album_err_local": "Impossible d'ajouter des éléments locaux aux albums pour le moment, étape ignorée",
|
||||||
"home_page_add_to_album_success": "{added} éléments ajoutés à l'album {album}.",
|
"home_page_add_to_album_success": "{added} éléments ajoutés à l'album {album}.",
|
||||||
@@ -295,6 +304,8 @@
|
|||||||
"memories_check_back_tomorrow": "Revenez demain pour d'autres souvenirs",
|
"memories_check_back_tomorrow": "Revenez demain pour d'autres souvenirs",
|
||||||
"memories_start_over": "Recommencer",
|
"memories_start_over": "Recommencer",
|
||||||
"memories_swipe_to_close": "Balayez vers le haut pour fermer",
|
"memories_swipe_to_close": "Balayez vers le haut pour fermer",
|
||||||
|
"memories_year_ago": "Il y a un an",
|
||||||
|
"memories_years_ago": "Il y a {} ans",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "Photos avec mouvement",
|
"motion_photos_page_title": "Photos avec mouvement",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "Impossible de modifier la date d'un élément d'actif en lecture seule.",
|
"multiselect_grid_edit_date_time_err_read_only": "Impossible de modifier la date d'un élément d'actif en lecture seule.",
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
"advanced_settings_log_level_title": "רמת תיעוד אירועים: {}",
|
"advanced_settings_log_level_title": "רמת תיעוד אירועים: {}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "חלק מהמכשירים הם אייטים מאד לטעון תמונות ממוזערות מנכסים שבמכשיר. הפעל הגדרה זו כדי לטעון תמונות מרוחקות במקום.",
|
"advanced_settings_prefer_remote_subtitle": "חלק מהמכשירים הם אייטים מאד לטעון תמונות ממוזערות מנכסים שבמכשיר. הפעל הגדרה זו כדי לטעון תמונות מרוחקות במקום.",
|
||||||
"advanced_settings_prefer_remote_title": "העדף תמונות מרוחקות",
|
"advanced_settings_prefer_remote_title": "העדף תמונות מרוחקות",
|
||||||
|
"advanced_settings_proxy_headers_subtitle": "Define proxy headers Immich should send with each network request",
|
||||||
|
"advanced_settings_proxy_headers_title": "Proxy Headers",
|
||||||
"advanced_settings_self_signed_ssl_subtitle": "מדלג על אימות תעודת SSL עבור נקודת הקצה של השרת. דרוש עבור תעודות בחתימה עצמית.",
|
"advanced_settings_self_signed_ssl_subtitle": "מדלג על אימות תעודת SSL עבור נקודת הקצה של השרת. דרוש עבור תעודות בחתימה עצמית.",
|
||||||
"advanced_settings_self_signed_ssl_title": "התר תעודות SSL בחתימה עצמית",
|
"advanced_settings_self_signed_ssl_title": "התר תעודות SSL בחתימה עצמית",
|
||||||
"advanced_settings_tile_subtitle": "הגדרות משתמש מתקדם",
|
"advanced_settings_tile_subtitle": "הגדרות משתמש מתקדם",
|
||||||
@@ -25,11 +27,11 @@
|
|||||||
"album_viewer_appbar_delete_confirm": "האם אתה בטוח שברצונך למחוק את האלבום מהחשבון שלך?",
|
"album_viewer_appbar_delete_confirm": "האם אתה בטוח שברצונך למחוק את האלבום מהחשבון שלך?",
|
||||||
"album_viewer_appbar_share_delete": "מחק אלבום",
|
"album_viewer_appbar_share_delete": "מחק אלבום",
|
||||||
"album_viewer_appbar_share_err_delete": "מחיקת אלבום נכשלה",
|
"album_viewer_appbar_share_err_delete": "מחיקת אלבום נכשלה",
|
||||||
"album_viewer_appbar_share_err_leave": "עזיבת אלבום נכשלה",
|
"album_viewer_appbar_share_err_leave": "עזיבת האלבום נכשלה",
|
||||||
"album_viewer_appbar_share_err_remove": "יש בעיות בהסרת נכסים מאלבום",
|
"album_viewer_appbar_share_err_remove": "יש בעיות בהסרת הנכסים מהאלבום",
|
||||||
"album_viewer_appbar_share_err_title": "נכשל בשינוי כותרת אלבום",
|
"album_viewer_appbar_share_err_title": "נכשל בשינוי כותרת האלבום",
|
||||||
"album_viewer_appbar_share_leave": "עזוב אלבום",
|
"album_viewer_appbar_share_leave": "עזוב אלבום",
|
||||||
"album_viewer_appbar_share_remove": "הסר מאלבום",
|
"album_viewer_appbar_share_remove": "הסרה מאלבום",
|
||||||
"album_viewer_appbar_share_to": "שתף עם",
|
"album_viewer_appbar_share_to": "שתף עם",
|
||||||
"album_viewer_page_share_add_users": "הוסף משתמשים",
|
"album_viewer_page_share_add_users": "הוסף משתמשים",
|
||||||
"all_people_page_title": "אנשים",
|
"all_people_page_title": "אנשים",
|
||||||
@@ -59,56 +61,56 @@
|
|||||||
"backup_album_selection_page_total_assets": "סה״כ נכסים ייחודיים",
|
"backup_album_selection_page_total_assets": "סה״כ נכסים ייחודיים",
|
||||||
"backup_all": "הכל",
|
"backup_all": "הכל",
|
||||||
"backup_background_service_backup_failed_message": "נכשל בגיבוי נכסים. מנסה שוב...",
|
"backup_background_service_backup_failed_message": "נכשל בגיבוי נכסים. מנסה שוב...",
|
||||||
"backup_background_service_connection_failed_message": "נכשל להתחבר לשרת. מנסה שוב...",
|
"backup_background_service_connection_failed_message": "נכשל בהתחברות לשרת. מנסה שוב...",
|
||||||
"backup_background_service_current_upload_notification": "מעלה {}",
|
"backup_background_service_current_upload_notification": "מגבה {}",
|
||||||
"backup_background_service_default_notification": "מחפש נכסים חדשים...",
|
"backup_background_service_default_notification": "מחפש נכסים חדשים...",
|
||||||
"backup_background_service_error_title": "שגיאת גיבוי",
|
"backup_background_service_error_title": "שגיאת גיבוי",
|
||||||
"backup_background_service_in_progress_notification": "מגבה את הנכסים שלך...",
|
"backup_background_service_in_progress_notification": "מגבה את הנכסים שלך...",
|
||||||
"backup_background_service_upload_failure_notification": "נכשל להעלות {}",
|
"backup_background_service_upload_failure_notification": "נכשל בגיבוי {}",
|
||||||
"backup_controller_page_albums": "אלבומי גיבוי",
|
"backup_controller_page_albums": "אלבומים לגיבוי",
|
||||||
"backup_controller_page_background_app_refresh_disabled_content": "אפשר רענון אפליקציה ברקע בהגדרות > כללי > רענון אפליקציה ברקע כדי להשתמש בגיבוי ברקע.",
|
"backup_controller_page_background_app_refresh_disabled_content": "אפשר רענון אפליקציה ברקע בהגדרות > כללי > רענון אפליקציה ברקע כדי להשתמש בגיבוי ברקע.",
|
||||||
"backup_controller_page_background_app_refresh_disabled_title": "רענון אפליקציה ברקע מושבת",
|
"backup_controller_page_background_app_refresh_disabled_title": "רענון אפליקציה ברקע מושבת",
|
||||||
"backup_controller_page_background_app_refresh_enable_button_text": "לך להגדרות",
|
"backup_controller_page_background_app_refresh_enable_button_text": "לך להגדרות",
|
||||||
"backup_controller_page_background_battery_info_link": "הראה לי איך",
|
"backup_controller_page_background_battery_info_link": "הראה לי איך",
|
||||||
"backup_controller_page_background_battery_info_message": "עבור חווית גיבוי ברקע הכי טובה, נא להשבית את כל מיטובי הסוללה המגבילים פעילות ברקע עבור Immich.\n\nמכיוון שזה תלוי מכשיר, בבקשה חפש/י את המידע הנדרש עבור יצרן המכשיר שלך.",
|
"backup_controller_page_background_battery_info_message": "עבור חווית גיבוי ברקע הטובה ביותר, נא להשבית את כל מיטובי הסוללה המגבילים פעילות ברקע עבור Immich.\n\nמכיוון שזה תלוי מכשיר, בבקשה חפש/י את המידע הנדרש עבור יצרן המכשיר שלך.",
|
||||||
"backup_controller_page_background_battery_info_ok": "בסדר",
|
"backup_controller_page_background_battery_info_ok": "בסדר",
|
||||||
"backup_controller_page_background_battery_info_title": "מיטובי סוללה",
|
"backup_controller_page_background_battery_info_title": "מיטובי סוללה",
|
||||||
"backup_controller_page_background_charging": "רק בעת טעינה",
|
"backup_controller_page_background_charging": "רק בטעינה",
|
||||||
"backup_controller_page_background_configure_error": "נכשל בהגדרת תצורת שירות הרקע",
|
"backup_controller_page_background_configure_error": "נכשל בהגדרת תצורת שירות הרקע",
|
||||||
"backup_controller_page_background_delay": "דחה גיבוי נכסים חדשים: {}",
|
"backup_controller_page_background_delay": "דחה גיבוי נכסים חדשים: {}",
|
||||||
"backup_controller_page_background_description": "הפעל את השירות רקע כדי לגבות באופן אוטומטי כל נכס חדש ללא צורך לפתוח את היישום",
|
"backup_controller_page_background_description": "הפעל את השירות רקע כדי לגבות באופן אוטומטי כל נכס חדש גם מבלי לפתוח את היישום",
|
||||||
"backup_controller_page_background_is_off": "גיבוי אוטומטי ברקע כבוי",
|
"backup_controller_page_background_is_off": "גיבוי אוטומטי ברקע כבוי",
|
||||||
"backup_controller_page_background_is_on": "גיבוי אוטומטי ברקע מופעל",
|
"backup_controller_page_background_is_on": "גיבוי אוטומטי ברקע מופעל",
|
||||||
"backup_controller_page_background_turn_off": "כבה שירות ברקע",
|
"backup_controller_page_background_turn_off": "כבה שירות גיבוי ברקע",
|
||||||
"backup_controller_page_background_turn_on": "הפעל שירות ברקע",
|
"backup_controller_page_background_turn_on": "הפעל שירות גיבוי ברקע",
|
||||||
"backup_controller_page_background_wifi": "רק ברשת אלחוטית",
|
"backup_controller_page_background_wifi": "רק ברשת אלחוטית",
|
||||||
"backup_controller_page_backup": "גובו",
|
"backup_controller_page_backup": "גיבוי",
|
||||||
"backup_controller_page_backup_selected": "נבחרו:",
|
"backup_controller_page_backup_selected": "נבחרו:",
|
||||||
"backup_controller_page_backup_sub": "תמונות וסרטונים מגובים",
|
"backup_controller_page_backup_sub": "תמונות וסרטונים מגובים",
|
||||||
"backup_controller_page_cancel": "ביטול",
|
"backup_controller_page_cancel": "ביטול",
|
||||||
"backup_controller_page_created": "נוצר ב: {}",
|
"backup_controller_page_created": "נוצר ב: {}",
|
||||||
"backup_controller_page_desc_backup": "הפעל גיבוי חזית כדי להעלות באופן אוטומטי נכסים חדשים לשרת כשפותחים את היישום.",
|
"backup_controller_page_desc_backup": "הפעל גיבוי בתוך היישום כדי להעלות באופן אוטומטי נכסים חדשים לשרת כשפותחים את היישום.",
|
||||||
"backup_controller_page_excluded": "הוחרגו",
|
"backup_controller_page_excluded": "הוחרגו:",
|
||||||
"backup_controller_page_failed": "נכשל ({})",
|
"backup_controller_page_failed": "נכשל ({})",
|
||||||
"backup_controller_page_filename": "שם קובץ: {} [{}]",
|
"backup_controller_page_filename": "שם קובץ: {} [{}]",
|
||||||
"backup_controller_page_id": "מזהה: {}",
|
"backup_controller_page_id": "מזהה: {}",
|
||||||
"backup_controller_page_info": "פרטי גיבוי",
|
"backup_controller_page_info": "פרטי גיבוי",
|
||||||
"backup_controller_page_none_selected": "לא נבחרו",
|
"backup_controller_page_none_selected": "לא נבחרו",
|
||||||
"backup_controller_page_remainder": "בתור לגיבוי",
|
"backup_controller_page_remainder": "בהמתנה לגיבוי",
|
||||||
"backup_controller_page_remainder_sub": "תמונות וסרטונים שנותרו לגבות מתוך בחירה",
|
"backup_controller_page_remainder_sub": "תמונות וסרטונים שנותרו לגבות מתוך בחירה",
|
||||||
"backup_controller_page_select": "בחר",
|
"backup_controller_page_select": "בחר",
|
||||||
"backup_controller_page_server_storage": "אחסון שרת",
|
"backup_controller_page_server_storage": "אחסון שרת",
|
||||||
"backup_controller_page_start_backup": "התחל גיבוי",
|
"backup_controller_page_start_backup": "התחל גיבוי",
|
||||||
"backup_controller_page_status_off": "גיבוי חזית אוטומטי כבוי",
|
"backup_controller_page_status_off": "גיבוי בתוך היישום אוטומטי כבוי",
|
||||||
"backup_controller_page_status_on": "גיבוי חזית אוטומטי מופעל",
|
"backup_controller_page_status_on": "גיבוי בתוך היישום אוטומטי מופעל",
|
||||||
"backup_controller_page_storage_format": "{} מתוך {} נוצלו",
|
"backup_controller_page_storage_format": "{} מתוך {} נוצלו",
|
||||||
"backup_controller_page_to_backup": "אלבומים לגבות",
|
"backup_controller_page_to_backup": "אלבומים לגבות",
|
||||||
"backup_controller_page_total": "סה״כ",
|
"backup_controller_page_total": "סה״כ",
|
||||||
"backup_controller_page_total_sub": "כל התמונות והסרטונים הייחודיים מאלבומים שנבחרו",
|
"backup_controller_page_total_sub": "כל התמונות והסרטונים הייחודיים מאלבומים שנבחרו",
|
||||||
"backup_controller_page_turn_off": "כבה גיבוי חזית",
|
"backup_controller_page_turn_off": "כיבוי גיבוי בתוך היישום",
|
||||||
"backup_controller_page_turn_on": "הפעל גיבוי חזית",
|
"backup_controller_page_turn_on": "הפעל גיבוי בתוך היישום",
|
||||||
"backup_controller_page_uploading_file_info": "מידע על הקובץ",
|
"backup_controller_page_uploading_file_info": "מידע על הקובץ",
|
||||||
"backup_err_only_album": "לא ניתן להסיר את האלבום היחידי",
|
"backup_err_only_album": "לא ניתן להסיר את האלבום",
|
||||||
"backup_info_card_assets": "נכסים",
|
"backup_info_card_assets": "נכסים",
|
||||||
"backup_manual_cancelled": "בוטל",
|
"backup_manual_cancelled": "בוטל",
|
||||||
"backup_manual_failed": "נכשל",
|
"backup_manual_failed": "נכשל",
|
||||||
@@ -203,6 +205,13 @@
|
|||||||
"favorites_page_title": "מועדפים",
|
"favorites_page_title": "מועדפים",
|
||||||
"haptic_feedback_switch": "הפעל משוב ברטט",
|
"haptic_feedback_switch": "הפעל משוב ברטט",
|
||||||
"haptic_feedback_title": "משוב ברטט",
|
"haptic_feedback_title": "משוב ברטט",
|
||||||
|
"header_settings_add_header_tip": "הוסף כותרת",
|
||||||
|
"header_settings_field_validator_msg": "ערך אינו יכול להיות ריק",
|
||||||
|
"header_settings_header_name_input": "שם כותרת",
|
||||||
|
"header_settings_header_value_input": "ערך כותרת",
|
||||||
|
"header_settings_page_title": "Proxy Headers",
|
||||||
|
"headers_settings_tile_subtitle": "Define proxy headers the app should send with each network request",
|
||||||
|
"headers_settings_tile_title": "Custom proxy headers",
|
||||||
"home_page_add_to_album_conflicts": "{added} נכסים נוספו לאלבום {album}. {failed} נכסים כבר נמצאים באלבום.",
|
"home_page_add_to_album_conflicts": "{added} נכסים נוספו לאלבום {album}. {failed} נכסים כבר נמצאים באלבום.",
|
||||||
"home_page_add_to_album_err_local": "לא ניתן להוסיף נכסים מקומיים לאלבום עדיין, מדלג",
|
"home_page_add_to_album_err_local": "לא ניתן להוסיף נכסים מקומיים לאלבום עדיין, מדלג",
|
||||||
"home_page_add_to_album_success": "{added} נכסים נוספו לאלבום {album}.",
|
"home_page_add_to_album_success": "{added} נכסים נוספו לאלבום {album}.",
|
||||||
@@ -245,7 +254,7 @@
|
|||||||
"login_form_back_button_text": "חזור",
|
"login_form_back_button_text": "חזור",
|
||||||
"login_form_button_text": "התחברות",
|
"login_form_button_text": "התחברות",
|
||||||
"login_form_email_hint": "yourmail@email.com",
|
"login_form_email_hint": "yourmail@email.com",
|
||||||
"login_form_endpoint_hint": "http://your-server-ip:port/API",
|
"login_form_endpoint_hint": "http://כתובת-השרת-שלך:פורט/API",
|
||||||
"login_form_endpoint_url": "כתובת נקודת קצה השרת",
|
"login_form_endpoint_url": "כתובת נקודת קצה השרת",
|
||||||
"login_form_err_http": "נא לציין //:htttp או //:https",
|
"login_form_err_http": "נא לציין //:htttp או //:https",
|
||||||
"login_form_err_invalid_email": "דוא\"ל שגוי",
|
"login_form_err_invalid_email": "דוא\"ל שגוי",
|
||||||
@@ -254,7 +263,7 @@
|
|||||||
"login_form_err_trailing_whitespace": "רווח לבן נגרר",
|
"login_form_err_trailing_whitespace": "רווח לבן נגרר",
|
||||||
"login_form_failed_get_oauth_server_config": "שגיאה בהתחברות באמצעות OAuth, בדוק את כתובת URL של השרת",
|
"login_form_failed_get_oauth_server_config": "שגיאה בהתחברות באמצעות OAuth, בדוק את כתובת URL של השרת",
|
||||||
"login_form_failed_get_oauth_server_disable": "תכונת OAuth לא זמינה בשרת זה",
|
"login_form_failed_get_oauth_server_disable": "תכונת OAuth לא זמינה בשרת זה",
|
||||||
"login_form_failed_login": "שגיאה בהכנסתך למערכת, בדוק את כתובת השרת, דוא\"ל וסיסמה",
|
"login_form_failed_login": "שגיאה בכניסה למערכת, בדוק את כתובת השרת, דוא\"ל וסיסמה",
|
||||||
"login_form_handshake_exception": "ארעה חריגת לחיצת יד עם השרת. אפשר תמיכה בתעודה בחתימה עצמית בהגדרות אם את/ה משתמש/ת בתעודה בחתימה עצמית.",
|
"login_form_handshake_exception": "ארעה חריגת לחיצת יד עם השרת. אפשר תמיכה בתעודה בחתימה עצמית בהגדרות אם את/ה משתמש/ת בתעודה בחתימה עצמית.",
|
||||||
"login_form_label_email": "דוא\"ל",
|
"login_form_label_email": "דוא\"ל",
|
||||||
"login_form_label_password": "סיסמה",
|
"login_form_label_password": "סיסמה",
|
||||||
@@ -295,6 +304,8 @@
|
|||||||
"memories_check_back_tomorrow": "זיכרונות חדשים יופיעו מחר",
|
"memories_check_back_tomorrow": "זיכרונות חדשים יופיעו מחר",
|
||||||
"memories_start_over": "התחל מחדש",
|
"memories_start_over": "התחל מחדש",
|
||||||
"memories_swipe_to_close": "החלק למעלה לסגירה",
|
"memories_swipe_to_close": "החלק למעלה לסגירה",
|
||||||
|
"memories_year_ago": "לפני שנה",
|
||||||
|
"memories_years_ago": "לפני {} שנים",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "תמונות עם תנועה",
|
"motion_photos_page_title": "תמונות עם תנועה",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "לא ניתן לערוך תאריך של נכס(ים) לקריאה בלבד, מדלג",
|
"multiselect_grid_edit_date_time_err_read_only": "לא ניתן לערוך תאריך של נכס(ים) לקריאה בלבד, מדלג",
|
||||||
@@ -306,7 +317,7 @@
|
|||||||
"notification_permission_list_tile_content": "הענק הרשאה כדי לאפשר התראות",
|
"notification_permission_list_tile_content": "הענק הרשאה כדי לאפשר התראות",
|
||||||
"notification_permission_list_tile_enable_button": "אפשר התראות",
|
"notification_permission_list_tile_enable_button": "אפשר התראות",
|
||||||
"notification_permission_list_tile_title": "הרשאת התראה",
|
"notification_permission_list_tile_title": "הרשאת התראה",
|
||||||
"partner_list_user_photos": "תמונות משתמש",
|
"partner_list_user_photos": "תמונות של {user}",
|
||||||
"partner_list_view_all": "הצג הכל",
|
"partner_list_view_all": "הצג הכל",
|
||||||
"partner_page_add_partner": "הוספת שותף",
|
"partner_page_add_partner": "הוספת שותף",
|
||||||
"partner_page_empty_message": "התמונות שלך עדיין לא משותפות עם אף שותף",
|
"partner_page_empty_message": "התמונות שלך עדיין לא משותפות עם אף שותף",
|
||||||
@@ -328,10 +339,10 @@
|
|||||||
"permission_onboarding_permission_limited": "הרשאה מוגבלת. כדי לתת לImmich לגבות ולנהל את כל אוסף הגלריה שלך, הענק הרשאה לתמונות וסרטונים בהגדרות.",
|
"permission_onboarding_permission_limited": "הרשאה מוגבלת. כדי לתת לImmich לגבות ולנהל את כל אוסף הגלריה שלך, הענק הרשאה לתמונות וסרטונים בהגדרות.",
|
||||||
"permission_onboarding_request": "Immich דורש הרשאה כדי לראות את התמונות והסרטונים שלך.",
|
"permission_onboarding_request": "Immich דורש הרשאה כדי לראות את התמונות והסרטונים שלך.",
|
||||||
"preferences_settings_title": "העדפות",
|
"preferences_settings_title": "העדפות",
|
||||||
"profile_drawer_app_logs": "יומנים",
|
"profile_drawer_app_logs": "לוגים",
|
||||||
"profile_drawer_client_out_of_date_major": "האפליקציה לנייד אינה עדכנית. נא לעדכן לגרסה האחרונה.",
|
"profile_drawer_client_out_of_date_major": "האפליקציה לנייד אינה עדכנית. נא לעדכן לגרסה האחרונה.",
|
||||||
"profile_drawer_client_out_of_date_minor": "האפליקציה לנייד אינה עדכנית. נא לעדכן לגרסה האחרונה.",
|
"profile_drawer_client_out_of_date_minor": "האפליקציה לנייד אינה עדכנית. נא לעדכן לגרסה האחרונה.",
|
||||||
"profile_drawer_client_server_up_to_date": "גרסת הלקוח והשרת מעודכנים",
|
"profile_drawer_client_server_up_to_date": "גרסת האפליקציה והשרת מעודכנים",
|
||||||
"profile_drawer_documentation": "תיעוד",
|
"profile_drawer_documentation": "תיעוד",
|
||||||
"profile_drawer_github": "GitHub",
|
"profile_drawer_github": "GitHub",
|
||||||
"profile_drawer_server_out_of_date_major": "השרת אינו עדכני. נא לעדכן לגרסה האחרונה.",
|
"profile_drawer_server_out_of_date_major": "השרת אינו עדכני. נא לעדכן לגרסה האחרונה.",
|
||||||
@@ -342,7 +353,7 @@
|
|||||||
"recently_added_page_title": "נוסף לאחרונה",
|
"recently_added_page_title": "נוסף לאחרונה",
|
||||||
"scaffold_body_error_occurred": "אירעה שגיאה",
|
"scaffold_body_error_occurred": "אירעה שגיאה",
|
||||||
"search_bar_hint": "חפש/י בתמונות שלך",
|
"search_bar_hint": "חפש/י בתמונות שלך",
|
||||||
"search_filter_apply": "החל מסנן",
|
"search_filter_apply": "סינון",
|
||||||
"search_filter_camera_make": "נוצר ע\"י",
|
"search_filter_camera_make": "נוצר ע\"י",
|
||||||
"search_filter_camera_model": "דגם",
|
"search_filter_camera_model": "דגם",
|
||||||
"search_filter_display_option_archive": "ארכיון",
|
"search_filter_display_option_archive": "ארכיון",
|
||||||
@@ -394,7 +405,7 @@
|
|||||||
"setting_image_viewer_title": "תמונות",
|
"setting_image_viewer_title": "תמונות",
|
||||||
"setting_languages_apply": "החל",
|
"setting_languages_apply": "החל",
|
||||||
"setting_languages_title": "שפות",
|
"setting_languages_title": "שפות",
|
||||||
"setting_notifications_notify_failures_grace_period": "להודיע על כשלים בגיבוי ברקע: {}",
|
"setting_notifications_notify_failures_grace_period": "הודיע על כשלים בגיבוי ברקע: {}",
|
||||||
"setting_notifications_notify_hours": "{} שעות",
|
"setting_notifications_notify_hours": "{} שעות",
|
||||||
"setting_notifications_notify_immediately": "באופן מיידי",
|
"setting_notifications_notify_immediately": "באופן מיידי",
|
||||||
"setting_notifications_notify_minutes": "{} דקות",
|
"setting_notifications_notify_minutes": "{} דקות",
|
||||||
@@ -480,12 +491,12 @@
|
|||||||
"sharing_page_empty_list": "רשימה ריקה",
|
"sharing_page_empty_list": "רשימה ריקה",
|
||||||
"sharing_silver_appbar_create_shared_album": "אלבום משותף חדש",
|
"sharing_silver_appbar_create_shared_album": "אלבום משותף חדש",
|
||||||
"sharing_silver_appbar_shared_links": "קישורים משותפים",
|
"sharing_silver_appbar_shared_links": "קישורים משותפים",
|
||||||
"sharing_silver_appbar_share_partner": "שתף עם שותף",
|
"sharing_silver_appbar_share_partner": "שיתוף עם שותף",
|
||||||
"tab_controller_nav_library": "ספרייה",
|
"tab_controller_nav_library": "ספרייה",
|
||||||
"tab_controller_nav_photos": "תמונות",
|
"tab_controller_nav_photos": "תמונות",
|
||||||
"tab_controller_nav_search": "חיפוש",
|
"tab_controller_nav_search": "חיפוש",
|
||||||
"tab_controller_nav_sharing": "שיתוף",
|
"tab_controller_nav_sharing": "שיתוף",
|
||||||
"theme_setting_asset_list_storage_indicator_title": "הראה מחוון אחסון על אריחי נכסים",
|
"theme_setting_asset_list_storage_indicator_title": "הראה מחוון אחסון על גבי התמונות",
|
||||||
"theme_setting_asset_list_tiles_per_row_title": "מספר נכסים בכל שורה ({})",
|
"theme_setting_asset_list_tiles_per_row_title": "מספר נכסים בכל שורה ({})",
|
||||||
"theme_setting_dark_mode_switch": "מצב כהה",
|
"theme_setting_dark_mode_switch": "מצב כהה",
|
||||||
"theme_setting_image_viewer_quality_subtitle": "התאם את האיכות של תצוגת התמונות המפורטת",
|
"theme_setting_image_viewer_quality_subtitle": "התאם את האיכות של תצוגת התמונות המפורטת",
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
"advanced_settings_log_level_title": "Log level: {}",
|
"advanced_settings_log_level_title": "Log level: {}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "Some devices are painfully slow to load thumbnails from assets on the device. Activate this setting to load remote images instead.",
|
"advanced_settings_prefer_remote_subtitle": "Some devices are painfully slow to load thumbnails from assets on the device. Activate this setting to load remote images instead.",
|
||||||
"advanced_settings_prefer_remote_title": "Prefer remote images",
|
"advanced_settings_prefer_remote_title": "Prefer remote images",
|
||||||
|
"advanced_settings_proxy_headers_subtitle": "Define proxy headers Immich should send with each network request",
|
||||||
|
"advanced_settings_proxy_headers_title": "Proxy Headers",
|
||||||
"advanced_settings_self_signed_ssl_subtitle": "Skips SSL certificate verification for the server endpoint. Required for self-signed certificates.",
|
"advanced_settings_self_signed_ssl_subtitle": "Skips SSL certificate verification for the server endpoint. Required for self-signed certificates.",
|
||||||
"advanced_settings_self_signed_ssl_title": "Allow self-signed SSL certificates",
|
"advanced_settings_self_signed_ssl_title": "Allow self-signed SSL certificates",
|
||||||
"advanced_settings_tile_subtitle": "Advanced user's settings",
|
"advanced_settings_tile_subtitle": "Advanced user's settings",
|
||||||
@@ -203,6 +205,13 @@
|
|||||||
"favorites_page_title": "Favorites",
|
"favorites_page_title": "Favorites",
|
||||||
"haptic_feedback_switch": "Enable haptic feedback",
|
"haptic_feedback_switch": "Enable haptic feedback",
|
||||||
"haptic_feedback_title": "Haptic Feedback",
|
"haptic_feedback_title": "Haptic Feedback",
|
||||||
|
"header_settings_add_header_tip": "Add Header",
|
||||||
|
"header_settings_field_validator_msg": "Value cannot be empty",
|
||||||
|
"header_settings_header_name_input": "Header name",
|
||||||
|
"header_settings_header_value_input": "Header value",
|
||||||
|
"header_settings_page_title": "Proxy Headers",
|
||||||
|
"headers_settings_tile_subtitle": "Define proxy headers the app should send with each network request",
|
||||||
|
"headers_settings_tile_title": "Custom proxy headers",
|
||||||
"home_page_add_to_album_conflicts": "Added {added} assets to album {album}. {failed} assets are already in the album.",
|
"home_page_add_to_album_conflicts": "Added {added} assets to album {album}. {failed} assets are already in the album.",
|
||||||
"home_page_add_to_album_err_local": "Can not add local assets to albums yet, skipping",
|
"home_page_add_to_album_err_local": "Can not add local assets to albums yet, skipping",
|
||||||
"home_page_add_to_album_success": "Added {added} assets to album {album}.",
|
"home_page_add_to_album_success": "Added {added} assets to album {album}.",
|
||||||
@@ -295,6 +304,8 @@
|
|||||||
"memories_check_back_tomorrow": "Check back tomorrow for more memories",
|
"memories_check_back_tomorrow": "Check back tomorrow for more memories",
|
||||||
"memories_start_over": "Start Over",
|
"memories_start_over": "Start Over",
|
||||||
"memories_swipe_to_close": "Swipe up to close",
|
"memories_swipe_to_close": "Swipe up to close",
|
||||||
|
"memories_year_ago": "A year ago",
|
||||||
|
"memories_years_ago": "{} years ago",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "Motion Photos",
|
"motion_photos_page_title": "Motion Photos",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
"advanced_settings_log_level_title": "Naplózás szintje: {}",
|
"advanced_settings_log_level_title": "Naplózás szintje: {}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "Néhány eszköz fájdalmasan lassan tölti be az eszközön lévő bélyegképeket. Ezzel a beállítással inkább a távoli képeket töltjük be helyette.",
|
"advanced_settings_prefer_remote_subtitle": "Néhány eszköz fájdalmasan lassan tölti be az eszközön lévő bélyegképeket. Ezzel a beállítással inkább a távoli képeket töltjük be helyette.",
|
||||||
"advanced_settings_prefer_remote_title": "Távoli képek előnyben részesítése",
|
"advanced_settings_prefer_remote_title": "Távoli képek előnyben részesítése",
|
||||||
|
"advanced_settings_proxy_headers_subtitle": "Define proxy headers Immich should send with each network request",
|
||||||
|
"advanced_settings_proxy_headers_title": "Proxy Headers",
|
||||||
"advanced_settings_self_signed_ssl_subtitle": "Nem ellenőrzi a szerver SSL tanúsítványát. Önaláírt tanúsítvány esetén szükséges beállítás.",
|
"advanced_settings_self_signed_ssl_subtitle": "Nem ellenőrzi a szerver SSL tanúsítványát. Önaláírt tanúsítvány esetén szükséges beállítás.",
|
||||||
"advanced_settings_self_signed_ssl_title": "Önaláírt SSL tanúsítványok engedélyezése",
|
"advanced_settings_self_signed_ssl_title": "Önaláírt SSL tanúsítványok engedélyezése",
|
||||||
"advanced_settings_tile_subtitle": "Haladó felhasználói beállítások",
|
"advanced_settings_tile_subtitle": "Haladó felhasználói beállítások",
|
||||||
@@ -203,6 +205,13 @@
|
|||||||
"favorites_page_title": "Kedvencek",
|
"favorites_page_title": "Kedvencek",
|
||||||
"haptic_feedback_switch": "Rezgéses visszajelzés engedélyezése",
|
"haptic_feedback_switch": "Rezgéses visszajelzés engedélyezése",
|
||||||
"haptic_feedback_title": "Rezgéses Visszajelzés",
|
"haptic_feedback_title": "Rezgéses Visszajelzés",
|
||||||
|
"header_settings_add_header_tip": "Add Header",
|
||||||
|
"header_settings_field_validator_msg": "Value cannot be empty",
|
||||||
|
"header_settings_header_name_input": "Header name",
|
||||||
|
"header_settings_header_value_input": "Header value",
|
||||||
|
"header_settings_page_title": "Proxy Headers",
|
||||||
|
"headers_settings_tile_subtitle": "Define proxy headers the app should send with each network request",
|
||||||
|
"headers_settings_tile_title": "Custom proxy headers",
|
||||||
"home_page_add_to_album_conflicts": "{added} elem hozzáadva a(z) \"{album}\" albumhoz. {failed} elem már eleve az albumban volt.",
|
"home_page_add_to_album_conflicts": "{added} elem hozzáadva a(z) \"{album}\" albumhoz. {failed} elem már eleve az albumban volt.",
|
||||||
"home_page_add_to_album_err_local": "Helyi elemeket még nem lehet albumba tenni. Kihagyjuk.",
|
"home_page_add_to_album_err_local": "Helyi elemeket még nem lehet albumba tenni. Kihagyjuk.",
|
||||||
"home_page_add_to_album_success": "{added} elem hozzáadva a(z) \"{album}\" albumhoz.",
|
"home_page_add_to_album_success": "{added} elem hozzáadva a(z) \"{album}\" albumhoz.",
|
||||||
@@ -295,6 +304,8 @@
|
|||||||
"memories_check_back_tomorrow": "Nézz vissza holnap újabb emlékekért",
|
"memories_check_back_tomorrow": "Nézz vissza holnap újabb emlékekért",
|
||||||
"memories_start_over": "Újrakezdés",
|
"memories_start_over": "Újrakezdés",
|
||||||
"memories_swipe_to_close": "Bezáráshoz söpörd ki felfelé",
|
"memories_swipe_to_close": "Bezáráshoz söpörd ki felfelé",
|
||||||
|
"memories_year_ago": "A year ago",
|
||||||
|
"memories_years_ago": "{} years ago",
|
||||||
"monthly_title_text_date_format": "y MMMM",
|
"monthly_title_text_date_format": "y MMMM",
|
||||||
"motion_photos_page_title": "Mozgó Fotók",
|
"motion_photos_page_title": "Mozgó Fotók",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "Csak-olvasható elem(ek) dátuma nem módosítható, ezért kihagyjuk",
|
"multiselect_grid_edit_date_time_err_read_only": "Csak-olvasható elem(ek) dátuma nem módosítható, ezért kihagyjuk",
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
"advanced_settings_log_level_title": "Livello log: {}",
|
"advanced_settings_log_level_title": "Livello log: {}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "Alcuni dispositivi sono molto lenti a caricare le anteprime delle immagini dal dispositivo. Attivare questa impostazione per caricare invece le immagini remote.",
|
"advanced_settings_prefer_remote_subtitle": "Alcuni dispositivi sono molto lenti a caricare le anteprime delle immagini dal dispositivo. Attivare questa impostazione per caricare invece le immagini remote.",
|
||||||
"advanced_settings_prefer_remote_title": "Preferisci immagini remote.",
|
"advanced_settings_prefer_remote_title": "Preferisci immagini remote.",
|
||||||
|
"advanced_settings_proxy_headers_subtitle": "Define proxy headers Immich should send with each network request",
|
||||||
|
"advanced_settings_proxy_headers_title": "Proxy Headers",
|
||||||
"advanced_settings_self_signed_ssl_subtitle": "Salta la verifica dei certificati SSL del server. Richiesto con l'uso di certificati self-signed.",
|
"advanced_settings_self_signed_ssl_subtitle": "Salta la verifica dei certificati SSL del server. Richiesto con l'uso di certificati self-signed.",
|
||||||
"advanced_settings_self_signed_ssl_title": "Consenti certificati SSL self-signed",
|
"advanced_settings_self_signed_ssl_title": "Consenti certificati SSL self-signed",
|
||||||
"advanced_settings_tile_subtitle": "Impostazioni aggiuntive utenti",
|
"advanced_settings_tile_subtitle": "Impostazioni aggiuntive utenti",
|
||||||
@@ -203,6 +205,13 @@
|
|||||||
"favorites_page_title": "Preferiti",
|
"favorites_page_title": "Preferiti",
|
||||||
"haptic_feedback_switch": "Abilita feedback aptico",
|
"haptic_feedback_switch": "Abilita feedback aptico",
|
||||||
"haptic_feedback_title": "Feedback aptico",
|
"haptic_feedback_title": "Feedback aptico",
|
||||||
|
"header_settings_add_header_tip": "Add Header",
|
||||||
|
"header_settings_field_validator_msg": "Value cannot be empty",
|
||||||
|
"header_settings_header_name_input": "Header name",
|
||||||
|
"header_settings_header_value_input": "Header value",
|
||||||
|
"header_settings_page_title": "Proxy Headers",
|
||||||
|
"headers_settings_tile_subtitle": "Define proxy headers the app should send with each network request",
|
||||||
|
"headers_settings_tile_title": "Custom proxy headers",
|
||||||
"home_page_add_to_album_conflicts": "Aggiunti {added} elementi all'album {album}. {failed} elementi erano già presenti nell'album.",
|
"home_page_add_to_album_conflicts": "Aggiunti {added} elementi all'album {album}. {failed} elementi erano già presenti nell'album.",
|
||||||
"home_page_add_to_album_err_local": "Non puoi aggiungere in album risorse non ancora caricate, azione ignorata",
|
"home_page_add_to_album_err_local": "Non puoi aggiungere in album risorse non ancora caricate, azione ignorata",
|
||||||
"home_page_add_to_album_success": "Aggiunti {added} elementi all'album {album}",
|
"home_page_add_to_album_success": "Aggiunti {added} elementi all'album {album}",
|
||||||
@@ -295,6 +304,8 @@
|
|||||||
"memories_check_back_tomorrow": "Torna domani per altri ricordi",
|
"memories_check_back_tomorrow": "Torna domani per altri ricordi",
|
||||||
"memories_start_over": "Ricomincia",
|
"memories_start_over": "Ricomincia",
|
||||||
"memories_swipe_to_close": "Scorri sopra per chiudere",
|
"memories_swipe_to_close": "Scorri sopra per chiudere",
|
||||||
|
"memories_year_ago": "A year ago",
|
||||||
|
"memories_years_ago": "{} years ago",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "Foto in movimento",
|
"motion_photos_page_title": "Foto in movimento",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "Non puoi modificare la data di risorse in sola lettura, azione ignorata",
|
"multiselect_grid_edit_date_time_err_read_only": "Non puoi modificare la data di risorse in sola lettura, azione ignorata",
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
"advanced_settings_log_level_title": "ログレベル: {}",
|
"advanced_settings_log_level_title": "ログレベル: {}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "デバイスによっては、デバイス上にあるサムネイルのロードに非常に時間がかかることがあります。このオプションをに有効にする事により、サーバーから直接画像をロードすることが可能です。",
|
"advanced_settings_prefer_remote_subtitle": "デバイスによっては、デバイス上にあるサムネイルのロードに非常に時間がかかることがあります。このオプションをに有効にする事により、サーバーから直接画像をロードすることが可能です。",
|
||||||
"advanced_settings_prefer_remote_title": "リモートを優先する",
|
"advanced_settings_prefer_remote_title": "リモートを優先する",
|
||||||
|
"advanced_settings_proxy_headers_subtitle": "Define proxy headers Immich should send with each network request",
|
||||||
|
"advanced_settings_proxy_headers_title": "Proxy Headers",
|
||||||
"advanced_settings_self_signed_ssl_subtitle": "SSLのチェックをスキップする。自己署名証明書が必要です。",
|
"advanced_settings_self_signed_ssl_subtitle": "SSLのチェックをスキップする。自己署名証明書が必要です。",
|
||||||
"advanced_settings_self_signed_ssl_title": "自己署名証明書を許可する",
|
"advanced_settings_self_signed_ssl_title": "自己署名証明書を許可する",
|
||||||
"advanced_settings_tile_subtitle": "追加ユーザー設定",
|
"advanced_settings_tile_subtitle": "追加ユーザー設定",
|
||||||
@@ -203,6 +205,13 @@
|
|||||||
"favorites_page_title": "お気に入り",
|
"favorites_page_title": "お気に入り",
|
||||||
"haptic_feedback_switch": "ハプティックフィードバック",
|
"haptic_feedback_switch": "ハプティックフィードバック",
|
||||||
"haptic_feedback_title": "ハプティックフィードバックを有効にする",
|
"haptic_feedback_title": "ハプティックフィードバックを有効にする",
|
||||||
|
"header_settings_add_header_tip": "Add Header",
|
||||||
|
"header_settings_field_validator_msg": "Value cannot be empty",
|
||||||
|
"header_settings_header_name_input": "Header name",
|
||||||
|
"header_settings_header_value_input": "Header value",
|
||||||
|
"header_settings_page_title": "Proxy Headers",
|
||||||
|
"headers_settings_tile_subtitle": "Define proxy headers the app should send with each network request",
|
||||||
|
"headers_settings_tile_title": "Custom proxy headers",
|
||||||
"home_page_add_to_album_conflicts": "{album}に{added}枚写真を追加しました。追加済みの{failed}枚はスキップしました。",
|
"home_page_add_to_album_conflicts": "{album}に{added}枚写真を追加しました。追加済みの{failed}枚はスキップしました。",
|
||||||
"home_page_add_to_album_err_local": "まだアップロードされてない項目は、アルバムに登録できません",
|
"home_page_add_to_album_err_local": "まだアップロードされてない項目は、アルバムに登録できません",
|
||||||
"home_page_add_to_album_success": "{album}に{added}枚写真を追加しました",
|
"home_page_add_to_album_success": "{album}に{added}枚写真を追加しました",
|
||||||
@@ -295,6 +304,8 @@
|
|||||||
"memories_check_back_tomorrow": "明日もう一度確認してください",
|
"memories_check_back_tomorrow": "明日もう一度確認してください",
|
||||||
"memories_start_over": "始める",
|
"memories_start_over": "始める",
|
||||||
"memories_swipe_to_close": "上にスワイプして閉じる",
|
"memories_swipe_to_close": "上にスワイプして閉じる",
|
||||||
|
"memories_year_ago": "A year ago",
|
||||||
|
"memories_years_ago": "{} years ago",
|
||||||
"monthly_title_text_date_format": "yyyy年 MM月",
|
"monthly_title_text_date_format": "yyyy年 MM月",
|
||||||
"motion_photos_page_title": "モーションフォト",
|
"motion_photos_page_title": "モーションフォト",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "読み取り専用の項目の日付を変更できません",
|
"multiselect_grid_edit_date_time_err_read_only": "読み取り専用の項目の日付を変更できません",
|
||||||
|
|||||||
@@ -4,12 +4,14 @@
|
|||||||
"action_common_clear": "지우기",
|
"action_common_clear": "지우기",
|
||||||
"action_common_confirm": "확인",
|
"action_common_confirm": "확인",
|
||||||
"action_common_update": "업데이트",
|
"action_common_update": "업데이트",
|
||||||
"add_to_album_bottom_sheet_added": "{album}에 추가",
|
"add_to_album_bottom_sheet_added": "{album}에 추가됨",
|
||||||
"add_to_album_bottom_sheet_already_exists": "{album}에 이미 포함되어 있습니다",
|
"add_to_album_bottom_sheet_already_exists": "{album}에 이미 존재함",
|
||||||
"advanced_settings_log_level_title": "로그 레벨: {}",
|
"advanced_settings_log_level_title": "로그 레벨: {}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "일부 디바이스에서는 디바이스에 있는 미디어의 썸네일을 로드하는 속도가 매우 느립니다. 대신 원격 이미지를 로드하려면 이 설정을 활성화하세요",
|
"advanced_settings_prefer_remote_subtitle": "일부 기기의 경우, 기기 내의 섬네일을 로드하는 속도가 매우 느립니다. 서버 이미지를 대신 로드하려면 이 설정을 활성화하세요.",
|
||||||
"advanced_settings_prefer_remote_title": "원격 이미지 선호",
|
"advanced_settings_prefer_remote_title": "서버 이미지 선호",
|
||||||
"advanced_settings_self_signed_ssl_subtitle": "서버 엔드포인트에 대한 SSL 인증서 확인을 건너뜁니다. 자체 서명 인증서에 필요합니다",
|
"advanced_settings_proxy_headers_subtitle": "각 네트워크 요청을 보낼 때 Immich가 사용할 프록시 헤더를 정의합니다.",
|
||||||
|
"advanced_settings_proxy_headers_title": "프록시 헤더",
|
||||||
|
"advanced_settings_self_signed_ssl_subtitle": "서버 엔드포인트에 대한 SSL 인증서 확인을 건너뜁니다. 자체 서명된 인증서를 사용하는 경우 활성화하세요.",
|
||||||
"advanced_settings_self_signed_ssl_title": "자체 서명된 SSL 인증서 허용",
|
"advanced_settings_self_signed_ssl_title": "자체 서명된 SSL 인증서 허용",
|
||||||
"advanced_settings_tile_subtitle": "고급 사용자 설정",
|
"advanced_settings_tile_subtitle": "고급 사용자 설정",
|
||||||
"advanced_settings_tile_title": "고급",
|
"advanced_settings_tile_title": "고급",
|
||||||
@@ -20,377 +22,386 @@
|
|||||||
"album_thumbnail_card_item": "1개 항목",
|
"album_thumbnail_card_item": "1개 항목",
|
||||||
"album_thumbnail_card_items": "{}개 항목",
|
"album_thumbnail_card_items": "{}개 항목",
|
||||||
"album_thumbnail_card_shared": " · 공유",
|
"album_thumbnail_card_shared": " · 공유",
|
||||||
"album_thumbnail_owned": "소유",
|
"album_thumbnail_owned": "소유함",
|
||||||
"album_thumbnail_shared_by": "공유자 {}",
|
"album_thumbnail_shared_by": "{}가 공유",
|
||||||
"album_viewer_appbar_delete_confirm": "계정에서 이 앨범을 삭제하시겠습니까?",
|
"album_viewer_appbar_delete_confirm": "이 앨범을 삭제하시겠습니까?",
|
||||||
"album_viewer_appbar_share_delete": "앨범 삭제",
|
"album_viewer_appbar_share_delete": "앨범 삭제",
|
||||||
"album_viewer_appbar_share_err_delete": "앨범 삭제 실패",
|
"album_viewer_appbar_share_err_delete": "앨범을 삭제하지 못했습니다.",
|
||||||
"album_viewer_appbar_share_err_leave": "앨범에서 나가지 못했습니다",
|
"album_viewer_appbar_share_err_leave": "앨범에서 나가지 못했습니다.",
|
||||||
"album_viewer_appbar_share_err_remove": "앨범에서 미디어를 제거하는 데 문제가 있습니다",
|
"album_viewer_appbar_share_err_remove": "앨범에서 선택한 항목을 제거하지 못했습니다.",
|
||||||
"album_viewer_appbar_share_err_title": "앨범 제목 변경 실패",
|
"album_viewer_appbar_share_err_title": "앨범 이름을 변경하지 못했습니다.",
|
||||||
"album_viewer_appbar_share_leave": "앨범 나가기",
|
"album_viewer_appbar_share_leave": "앨범 나가기",
|
||||||
"album_viewer_appbar_share_remove": "앨범에서 제거",
|
"album_viewer_appbar_share_remove": "앨범에서 제거",
|
||||||
"album_viewer_appbar_share_to": "공유 대상",
|
"album_viewer_appbar_share_to": "공유 대상",
|
||||||
"album_viewer_page_share_add_users": "사용자 추가",
|
"album_viewer_page_share_add_users": "사용자 추가",
|
||||||
"all_people_page_title": "사람",
|
"all_people_page_title": "인물",
|
||||||
"all_videos_page_title": "동영상",
|
"all_videos_page_title": "동영상",
|
||||||
"app_bar_signout_dialog_content": "정말 로그아웃하시겠습니까?",
|
"app_bar_signout_dialog_content": "정말 로그아웃하시겠습니까?",
|
||||||
"app_bar_signout_dialog_ok": "네",
|
"app_bar_signout_dialog_ok": "네",
|
||||||
"app_bar_signout_dialog_title": "로그 아웃",
|
"app_bar_signout_dialog_title": "로그아웃",
|
||||||
"archive_page_no_archived_assets": "보관된 미디어를 찾을 수 없습니다",
|
"archive_page_no_archived_assets": "보관된 항목 없음",
|
||||||
"archive_page_title": "보관 ({})",
|
"archive_page_title": "보관함 ({})",
|
||||||
"asset_action_delete_err_read_only": "읽기 전용 미디어를 삭제할 수 없어 건너뜁니다",
|
"asset_action_delete_err_read_only": "읽기 전용 콘텐츠를 삭제할 수 없습니다. 건너뜁니다.",
|
||||||
"asset_action_share_err_offline": "오프라인 미디어를 가져올 수 없어 건너뜁니다",
|
"asset_action_share_err_offline": "오프라인 콘텐츠를 불러올 수 없습니다. 건너뜁니다.",
|
||||||
"asset_list_group_by_sub_title": "그룹화 기준",
|
"asset_list_group_by_sub_title": "다음으로 그룹화",
|
||||||
"asset_list_layout_settings_dynamic_layout_title": "다이나믹 레이아웃",
|
"asset_list_layout_settings_dynamic_layout_title": "동적 레이아웃",
|
||||||
"asset_list_layout_settings_group_automatically": "자동",
|
"asset_list_layout_settings_group_automatically": "자동",
|
||||||
"asset_list_layout_settings_group_by": "다음으로 미디어 그룹화",
|
"asset_list_layout_settings_group_by": "다음으로 콘텐츠 그룹화",
|
||||||
"asset_list_layout_settings_group_by_month": "월",
|
"asset_list_layout_settings_group_by_month": "월",
|
||||||
"asset_list_layout_settings_group_by_month_day": "월 + 일",
|
"asset_list_layout_settings_group_by_month_day": "월 + 일",
|
||||||
"asset_list_layout_sub_title": "레이아웃",
|
"asset_list_layout_sub_title": "레이아웃",
|
||||||
"asset_list_settings_subtitle": "사진 배열 레이아웃 설정",
|
"asset_list_settings_subtitle": "사진 배열 레이아웃 설정",
|
||||||
"asset_list_settings_title": "사진 배열",
|
"asset_list_settings_title": "사진 배열",
|
||||||
"asset_viewer_settings_title": "미디어 뷰어",
|
"asset_viewer_settings_title": "보기 옵션",
|
||||||
"backup_album_selection_page_albums_device": "기기의 앨범({})",
|
"backup_album_selection_page_albums_device": "기기의 앨범 ({})",
|
||||||
"backup_album_selection_page_albums_tap": "포함하려면 탭하고 제외하려면 두 번 탭하세요",
|
"backup_album_selection_page_albums_tap": "포함하려면 한 번 누르고 제외하려면 두 번 누르세요.",
|
||||||
"backup_album_selection_page_assets_scatter": "미디어파일은 여러 앨범에 분산될 수 있습니다. 따라서 백업 프로세스 중에 앨범에서 포함하거나 제외할 수 있습니다.",
|
"backup_album_selection_page_assets_scatter": "콘텐츠는 여러 앨범에 분산될 수 있으며, 백업 작업 중에도 대상 앨범을 포함하거나 제외할 수 있습니다.",
|
||||||
"backup_album_selection_page_select_albums": "앨범 선택",
|
"backup_album_selection_page_select_albums": "앨범 선택",
|
||||||
"backup_album_selection_page_selection_info": "선택 정보",
|
"backup_album_selection_page_selection_info": "선택한 앨범 ",
|
||||||
"backup_album_selection_page_total_assets": "총 미디어파일 수",
|
"backup_album_selection_page_total_assets": "전체 항목",
|
||||||
"backup_all": "모두",
|
"backup_all": "모두",
|
||||||
"backup_background_service_backup_failed_message": "미디어파일을 백업하지 못했습니다. 다시 시도하는 중...",
|
"backup_background_service_backup_failed_message": "콘텐츠를 백업하지 못했습니다. 다시 시도하는 중...",
|
||||||
"backup_background_service_connection_failed_message": "서버에 연결하지 못했습니다. 다시 시도하는 중...",
|
"backup_background_service_connection_failed_message": "서버에 연결하지 못했습니다. 다시 시도하는 중...",
|
||||||
"backup_background_service_current_upload_notification": "{} 업로드 중",
|
"backup_background_service_current_upload_notification": "{} 업로드 중",
|
||||||
"backup_background_service_default_notification": "새 미디어파일 확인중...",
|
"backup_background_service_default_notification": "새 콘텐츠를 확인하고 있습니다...",
|
||||||
"backup_background_service_error_title": "백업 오류",
|
"backup_background_service_error_title": "백업 오류",
|
||||||
"backup_background_service_in_progress_notification": "미디어파일 백업 중...",
|
"backup_background_service_in_progress_notification": "콘텐츠를 백업하고 있습니다...",
|
||||||
"backup_background_service_upload_failure_notification": "{} 업로드 실패",
|
"backup_background_service_upload_failure_notification": "{} 업로드 실패",
|
||||||
"backup_controller_page_albums": "백업대상",
|
"backup_controller_page_albums": "백업할 앨범",
|
||||||
"backup_controller_page_background_app_refresh_disabled_content": "백그라운드 백업을 사용하려면 설정 > 일반 > 백그라운드 앱 새로 고침에서 백그라운드 앱 새로 고침을 활성화합니다",
|
"backup_controller_page_background_app_refresh_disabled_content": "백그라운드 백업을 사용하려면 설정 > 일반 > 백그라운드 앱 새로 고침에서 백그라운드 앱 새로 고침을 활성화하세요.",
|
||||||
"backup_controller_page_background_app_refresh_disabled_title": "백그라운드 앱 새로 고침 비활성화",
|
"backup_controller_page_background_app_refresh_disabled_title": "백그라운드 새로 고침 비활성화됨",
|
||||||
"backup_controller_page_background_app_refresh_enable_button_text": "설정으로 이동",
|
"backup_controller_page_background_app_refresh_enable_button_text": "설정으로 이동",
|
||||||
"backup_controller_page_background_battery_info_link": "사용 가이드",
|
"backup_controller_page_background_battery_info_link": "설정 방법",
|
||||||
"backup_controller_page_background_battery_info_message": "최상의 백업 환경을 위해 Immich 앱의 백그라운드 활동을 제한하는 배터리 최적화기능을 꺼주세요.\n\n휴대폰마다 설정방법이 다르므로 제조업체별로 설정방법을 확인하세요.",
|
"backup_controller_page_background_battery_info_message": "최상의 백그라운드 백업 환경을 위해, Immich의 백그라운드 활동을 제한하는 배터리 최적화를 비활성화하세요.\n\n설정 방법은 기기마다 다르므로, 제조 업체에서 관련 정보를 찾아보세요.",
|
||||||
"backup_controller_page_background_battery_info_ok": "확인",
|
"backup_controller_page_background_battery_info_ok": "확인",
|
||||||
"backup_controller_page_background_battery_info_title": "배터리 최적화",
|
"backup_controller_page_background_battery_info_title": "배터리 최적화",
|
||||||
"backup_controller_page_background_charging": "충전 중일 때만",
|
"backup_controller_page_background_charging": "충전 중에만",
|
||||||
"backup_controller_page_background_configure_error": "백그라운드 서비스를 구성하지 못했습니다",
|
"backup_controller_page_background_configure_error": "백그라운드 서비스 구성 실패",
|
||||||
"backup_controller_page_background_delay": "새 미디어파일 백업 지연: {}",
|
"backup_controller_page_background_delay": "새 콘텐츠 백업 간격: {}",
|
||||||
"backup_controller_page_background_description": "백그라운드 서비스를 켜서 앱을 열지 않고도 새 미디어파일을 자동으로 백업합니다.",
|
"backup_controller_page_background_description": "백그라운드 서비스를 활성화하면 앱을 열지 않고도 새 콘텐츠를 자동으로 백업할 수 있습니다.",
|
||||||
"backup_controller_page_background_is_off": "자동 백그라운드 백업이 꺼져 있습니다",
|
"backup_controller_page_background_is_off": "자동 백그라운드 백업이 비활성화되었습니다.",
|
||||||
"backup_controller_page_background_is_on": "자동 백그라운드 백업이 켜져 있습니다",
|
"backup_controller_page_background_is_on": "자동 백그라운드 백업이 활성화되었습니다.",
|
||||||
"backup_controller_page_background_turn_off": "백그라운드 서비스 끄기",
|
"backup_controller_page_background_turn_off": "백그라운드 서비스 비활성화",
|
||||||
"backup_controller_page_background_turn_on": "백그라운드 서비스 켜기",
|
"backup_controller_page_background_turn_on": "백그라운드 서비스 활성화",
|
||||||
"backup_controller_page_background_wifi": "WiFi에서만",
|
"backup_controller_page_background_wifi": "Wi-Fi를 통해서만 백업",
|
||||||
"backup_controller_page_backup": "백업",
|
"backup_controller_page_backup": "백업",
|
||||||
"backup_controller_page_backup_selected": "선택됨: ",
|
"backup_controller_page_backup_selected": "선택됨: ",
|
||||||
"backup_controller_page_backup_sub": "백업된 사진 및 비디오",
|
"backup_controller_page_backup_sub": "백업된 사진 및 동영상",
|
||||||
"backup_controller_page_cancel": "취소",
|
"backup_controller_page_cancel": "취소",
|
||||||
"backup_controller_page_created": "생성일: {}",
|
"backup_controller_page_created": "만든 날짜: {}",
|
||||||
"backup_controller_page_desc_backup": "새 미디어파일을 서버에 자동으로 업로드하려면 백업을 켜주세요.",
|
"backup_controller_page_desc_backup": "새 콘텐츠를 서버에 자동으로 백업하려면 백업을 활성화하세요.",
|
||||||
"backup_controller_page_excluded": "제외됨: ",
|
"backup_controller_page_excluded": "제외됨: ",
|
||||||
"backup_controller_page_failed": "실패함 ({})",
|
"backup_controller_page_failed": "실패 ({})",
|
||||||
"backup_controller_page_filename": "파일 이름: {} [{}]",
|
"backup_controller_page_filename": "파일명: {} [{}]",
|
||||||
"backup_controller_page_id": "ID: {}",
|
"backup_controller_page_id": "ID: {}",
|
||||||
"backup_controller_page_info": "정보",
|
"backup_controller_page_info": "백업 정보",
|
||||||
"backup_controller_page_none_selected": "선택되지 않음",
|
"backup_controller_page_none_selected": "선택한 항목 없음",
|
||||||
"backup_controller_page_remainder": "남은 백업파일",
|
"backup_controller_page_remainder": "남은 항목",
|
||||||
"backup_controller_page_remainder_sub": "백업 대기중인 남은 사진 및 비디오",
|
"backup_controller_page_remainder_sub": "선택한 항목 중 백업해야 할 남은 사진 및 동영상",
|
||||||
"backup_controller_page_select": "선택",
|
"backup_controller_page_select": "선택",
|
||||||
"backup_controller_page_server_storage": "서버 저장소",
|
"backup_controller_page_server_storage": "서버 스토리지",
|
||||||
"backup_controller_page_start_backup": "백업 시작",
|
"backup_controller_page_start_backup": "백업 시작",
|
||||||
"backup_controller_page_status_off": "백업이 꺼져 있습니다",
|
"backup_controller_page_status_off": "자동 백업이 비활성화되었습니다.",
|
||||||
"backup_controller_page_status_on": "백업이 켜져 있습니다",
|
"backup_controller_page_status_on": "자동 백업이 활성화되었습니다.",
|
||||||
"backup_controller_page_storage_format": "{}/{} 사용",
|
"backup_controller_page_storage_format": "{} 사용 중, 전체 {}",
|
||||||
"backup_controller_page_to_backup": "백업할 앨범",
|
"backup_controller_page_to_backup": "백업할 앨범 목록",
|
||||||
"backup_controller_page_total": "전체 백업대상",
|
"backup_controller_page_total": "전체",
|
||||||
"backup_controller_page_total_sub": "선택한 앨범의 모든 사진 및 비디오",
|
"backup_controller_page_total_sub": "선택한 앨범의 모든 사진 및 동영상",
|
||||||
"backup_controller_page_turn_off": "백업 끄기",
|
"backup_controller_page_turn_off": "백업 비활성화",
|
||||||
"backup_controller_page_turn_on": "백업 켜기",
|
"backup_controller_page_turn_on": "백업 활성화",
|
||||||
"backup_controller_page_uploading_file_info": "파일 정보 업로드 중",
|
"backup_controller_page_uploading_file_info": "파일 정보 업로드 중",
|
||||||
"backup_err_only_album": "유일한 앨범은 제거할 수 없습니다",
|
"backup_err_only_album": "유일한 앨범은 제거할 수 없습니다.",
|
||||||
"backup_info_card_assets": "미디어",
|
"backup_info_card_assets": "콘텐츠",
|
||||||
"backup_manual_cancelled": "취소됨",
|
"backup_manual_cancelled": "취소됨",
|
||||||
"backup_manual_failed": "실패",
|
"backup_manual_failed": "실패",
|
||||||
"backup_manual_in_progress": "업로드가 이미 진행 중입니다. 잠시 후 시도하세요",
|
"backup_manual_in_progress": "업로드가 이미 진행 중입니다. 잠시 후 시도하세요.",
|
||||||
"backup_manual_success": "성공",
|
"backup_manual_success": "성공",
|
||||||
"backup_manual_title": "업로드 상태",
|
"backup_manual_title": "업로드 상태",
|
||||||
"backup_options_page_title": "백업 옵션",
|
"backup_options_page_title": "백업 옵션",
|
||||||
"cache_settings_album_thumbnails": "라이브러리 페이지 썸네일 ({} 미디어)",
|
"cache_settings_album_thumbnails": "라이브러리 섬네일 ({})",
|
||||||
"cache_settings_clear_cache_button": "캐시 지우기",
|
"cache_settings_clear_cache_button": "캐시 지우기",
|
||||||
"cache_settings_clear_cache_button_title": "앱의 캐시를 지웁니다. 이 작업은 캐시가 다시 빌드될 때까지 앱의 성능에 상당한 영향을 미칩니다.",
|
"cache_settings_clear_cache_button_title": "앱 캐시를 지웁니다. 이 작업은 캐시가 다시 생성될 때까지 앱 성능에 상당한 영향을 미칠 수 있습니다.",
|
||||||
"cache_settings_duplicated_assets_clear_button": "클리어",
|
"cache_settings_duplicated_assets_clear_button": "지우기",
|
||||||
"cache_settings_duplicated_assets_subtitle": "앱에서 블랙리스트에 오른 사진 및 동영상",
|
"cache_settings_duplicated_assets_subtitle": "앱의 제외 대상인 사진 및 동영상",
|
||||||
"cache_settings_duplicated_assets_title": "중복된 미디어 ({})",
|
"cache_settings_duplicated_assets_title": "중복 항목 ({})",
|
||||||
"cache_settings_image_cache_size": "이미재 캐시 크기 ({} 미디어)",
|
"cache_settings_image_cache_size": "이미지 캐시 크기 ({})",
|
||||||
"cache_settings_statistics_album": "라이브러리 썸네일",
|
"cache_settings_statistics_album": "라이브러리 섬네일",
|
||||||
"cache_settings_statistics_assets": "{} 미디어 ({})",
|
"cache_settings_statistics_assets": "{} 항목 ({})",
|
||||||
"cache_settings_statistics_full": "전체 이미지",
|
"cache_settings_statistics_full": "전체 이미지",
|
||||||
"cache_settings_statistics_shared": "공유 앨범 썸네일",
|
"cache_settings_statistics_shared": "공유 앨범 섬네일",
|
||||||
"cache_settings_statistics_thumbnail": "썸네일",
|
"cache_settings_statistics_thumbnail": "섬네일",
|
||||||
"cache_settings_statistics_title": "캐시 사용률",
|
"cache_settings_statistics_title": "캐시 사용률",
|
||||||
"cache_settings_subtitle": "Immich 앱의 캐싱 동작 제어",
|
"cache_settings_subtitle": "Immich 모바일 앱의 캐싱 동작 제어",
|
||||||
"cache_settings_thumbnail_size": "썸네일 캐시 크기 ({} 미디어)",
|
"cache_settings_thumbnail_size": "섬네일 캐시 크기 ({})",
|
||||||
"cache_settings_tile_subtitle": "로컬 저장소 동작 제어",
|
"cache_settings_tile_subtitle": "로컬 스토리지 동작 제어",
|
||||||
"cache_settings_tile_title": "로컬 저장소",
|
"cache_settings_tile_title": "로컬 스토리지",
|
||||||
"cache_settings_title": "캐시 설정",
|
"cache_settings_title": "캐시 설정",
|
||||||
"change_password_form_confirm_password": "비밀번호 확인",
|
"change_password_form_confirm_password": "현재 비밀번호 입력",
|
||||||
"change_password_form_description": "{name}님, 안녕하세요.\n\n시스템에 처음 로그인했거나 비밀번호 변경 요청이 있었습니다. 아래에 새 비밀번호를 입력하세요.",
|
"change_password_form_description": "안녕하세요. {name}님,\n\n시스템에 처음으로 로그인하거나, 비밀번호 변경 요청이 있었습니다. 아래에 새 비밀번호를 입력해주세요.",
|
||||||
"change_password_form_new_password": "새 비밀번호",
|
"change_password_form_new_password": "새 비밀번호 입력",
|
||||||
"change_password_form_password_mismatch": "비밀번호가 일치하지 않습니다",
|
"change_password_form_password_mismatch": "비밀번호가 일치하지 않습니다.",
|
||||||
"change_password_form_reenter_new_password": "새 비밀번호 재입력",
|
"change_password_form_reenter_new_password": "새 비밀번호 확인",
|
||||||
"common_add_to_album": "앨범에 추가",
|
"common_add_to_album": "앨범에 추가",
|
||||||
"common_change_password": "비밀번호 변경",
|
"common_change_password": "비밀번호 변경",
|
||||||
"common_create_new_album": "새 앨범 만들기",
|
"common_create_new_album": "새 앨범 생성",
|
||||||
"common_server_error": "네트워크 연결을 확인하고 서버에 연결할 수 있는지, 앱/서버 버전이 호환되는지 확인하세요",
|
"common_server_error": "네트워크 연결 상태를 확인하고, 서버에 접속할 수 있는지, 앱/서버 버전이 호환되는지 확인해주세요.",
|
||||||
"common_shared": "공유됨",
|
"common_shared": "공유됨",
|
||||||
"control_bottom_app_bar_add_to_album": "앨범에 추가",
|
"control_bottom_app_bar_add_to_album": "앨범에 추가",
|
||||||
"control_bottom_app_bar_album_info": "{} 항목",
|
"control_bottom_app_bar_album_info": "{}개 항목",
|
||||||
"control_bottom_app_bar_album_info_shared": "{} 항목 · 공유됨",
|
"control_bottom_app_bar_album_info_shared": "{}개 항목 · 공유됨",
|
||||||
"control_bottom_app_bar_archive": "보관",
|
"control_bottom_app_bar_archive": "보관함",
|
||||||
"control_bottom_app_bar_create_new_album": "앨범 생성",
|
"control_bottom_app_bar_create_new_album": "새 앨범 생성",
|
||||||
"control_bottom_app_bar_delete": "삭제",
|
"control_bottom_app_bar_delete": "삭제",
|
||||||
"control_bottom_app_bar_delete_from_immich": "immich에서 삭제",
|
"control_bottom_app_bar_delete_from_immich": "Immich에서 삭제",
|
||||||
"control_bottom_app_bar_delete_from_local": "기기에서 삭제",
|
"control_bottom_app_bar_delete_from_local": "기기에서 삭제",
|
||||||
"control_bottom_app_bar_edit_location": "위치 수정",
|
"control_bottom_app_bar_edit_location": "위치 편집",
|
||||||
"control_bottom_app_bar_edit_time": "날짜 및 시간 수정",
|
"control_bottom_app_bar_edit_time": "날짜 및 시간 편집",
|
||||||
"control_bottom_app_bar_favorite": "즐겨찾기",
|
"control_bottom_app_bar_favorite": "즐겨찾기",
|
||||||
"control_bottom_app_bar_share": "공유",
|
"control_bottom_app_bar_share": "공유",
|
||||||
"control_bottom_app_bar_share_to": "공유 대상",
|
"control_bottom_app_bar_share_to": "공유 대상",
|
||||||
"control_bottom_app_bar_stack": "합치기",
|
"control_bottom_app_bar_stack": "스택",
|
||||||
"control_bottom_app_bar_trash_from_immich": "휴지통으로 이동",
|
"control_bottom_app_bar_trash_from_immich": "휴지통으로 이동",
|
||||||
"control_bottom_app_bar_unarchive": "보관 해제",
|
"control_bottom_app_bar_unarchive": "보관 해제",
|
||||||
"control_bottom_app_bar_unfavorite": "싫어요",
|
"control_bottom_app_bar_unfavorite": "즐겨찾기 해제",
|
||||||
"control_bottom_app_bar_upload": "업로드",
|
"control_bottom_app_bar_upload": "업로드",
|
||||||
"create_album_page_untitled": "제목없음",
|
"create_album_page_untitled": "제목 없음",
|
||||||
"create_shared_album_page_create": "만들기",
|
"create_shared_album_page_create": "생성",
|
||||||
"create_shared_album_page_share": "공유",
|
"create_shared_album_page_share": "공유",
|
||||||
"create_shared_album_page_share_add_assets": "사진 추가",
|
"create_shared_album_page_share_add_assets": "콘텐츠 추가",
|
||||||
"create_shared_album_page_share_select_photos": "사진 선택",
|
"create_shared_album_page_share_select_photos": "사진 선택",
|
||||||
"curated_location_page_title": "장소",
|
"curated_location_page_title": "장소",
|
||||||
"curated_object_page_title": "사물",
|
"curated_object_page_title": "사물",
|
||||||
"daily_title_text_date": "E, M월 d일",
|
"daily_title_text_date": "E, M월 d일",
|
||||||
"daily_title_text_date_year": "E, M월 d일, yyyy",
|
"daily_title_text_date_year": "E, M월 d일, yyyy",
|
||||||
"date_format": "yyyy년 M월 d일, EEEE • a h:mm",
|
"date_format": "yyyy년 M월 d일, EEEE • a h:mm",
|
||||||
"delete_dialog_alert": "이 항목은 Immich 및 휴대폰에서 영구적으로 삭제됩니다",
|
"delete_dialog_alert": "선택한 항목이 Immich 및 기기에서 영구적으로 삭제됩니다.",
|
||||||
"delete_dialog_alert_local": "이 아이템들은 장치에서 영구적으로 제거되지만 Immich 서버에서는 계속 사용할 수 있습니다",
|
"delete_dialog_alert_local": "선택한 항목이 이 기기에서 영구적으로 삭제됩니다. Immich 서버에서는 계속 사용할 수 있습니다.",
|
||||||
"delete_dialog_alert_local_non_backed_up": "일부 항목은 Immich에 백업되지 않으며 장치에서 영구적으로 제거됩니다",
|
"delete_dialog_alert_local_non_backed_up": "일부 항목은 Immich에 백업되지 않으며 기기에서 영구적으로 삭제됩니다.",
|
||||||
"delete_dialog_alert_remote": "이 아이템들은 Immich 서버에서 영구 삭제됩니다",
|
"delete_dialog_alert_remote": "선택한 항목이 Immich 서버에서 영구적으로 삭제됩니다.",
|
||||||
"delete_dialog_cancel": "취소",
|
"delete_dialog_cancel": "취소",
|
||||||
"delete_dialog_ok": "삭제",
|
"delete_dialog_ok": "삭제",
|
||||||
"delete_dialog_ok_force": "무조건 삭제",
|
"delete_dialog_ok_force": "무시하고 삭제",
|
||||||
"delete_dialog_title": "영구적으로 삭제",
|
"delete_dialog_title": "영구 삭제",
|
||||||
"delete_local_dialog_ok_backed_up_only": "백업된 항목만 삭제",
|
"delete_local_dialog_ok_backed_up_only": "백업된 항목만 삭제",
|
||||||
"delete_local_dialog_ok_force": "무조건 삭제",
|
"delete_local_dialog_ok_force": "무시하고 삭제",
|
||||||
"delete_shared_link_dialog_content": "이 공유 링크를 삭제하시겠습니까?",
|
"delete_shared_link_dialog_content": "이 공유 링크를 삭제하시겠습니까?",
|
||||||
"delete_shared_link_dialog_title": "공유 링크 삭제",
|
"delete_shared_link_dialog_title": "공유 링크 삭제",
|
||||||
"description_input_hint_text": "설명 추가",
|
"description_input_hint_text": "설명 추가...",
|
||||||
"description_input_submit_error": "설명 업데이트 오류, 자세한 내용은 로그를 확인하세요",
|
"description_input_submit_error": "설명을 업데이트하는 중 문제가 발생했습니다. 자세한 내용은 로그를 확인하세요.",
|
||||||
"edit_date_time_dialog_date_time": "날짜 및 시간",
|
"edit_date_time_dialog_date_time": "날짜 및 시간",
|
||||||
"edit_date_time_dialog_timezone": "타임존",
|
"edit_date_time_dialog_timezone": "시간대",
|
||||||
"edit_location_dialog_title": "위치",
|
"edit_location_dialog_title": "위치",
|
||||||
"exif_bottom_sheet_description": "설명 추가...",
|
"exif_bottom_sheet_description": "설명 추가...",
|
||||||
"exif_bottom_sheet_details": "상세정보",
|
"exif_bottom_sheet_details": "상세 정보",
|
||||||
"exif_bottom_sheet_location": "위치",
|
"exif_bottom_sheet_location": "위치",
|
||||||
"exif_bottom_sheet_location_add": "위치 지정",
|
"exif_bottom_sheet_location_add": "위치 추가",
|
||||||
"exif_bottom_sheet_people": "사람들",
|
"exif_bottom_sheet_people": "인물",
|
||||||
"exif_bottom_sheet_person_add_person": "이름 추가",
|
"exif_bottom_sheet_person_add_person": "이름 추가",
|
||||||
"experimental_settings_new_asset_list_subtitle": "진행중",
|
"experimental_settings_new_asset_list_subtitle": "진행 중",
|
||||||
"experimental_settings_new_asset_list_title": "실험적 사진 그리드 적용",
|
"experimental_settings_new_asset_list_title": "새 사진 배열 사용 (실험적)",
|
||||||
"experimental_settings_subtitle": "문제시 책임지지 않습니다!",
|
"experimental_settings_subtitle": "본인 책임 하에 사용하세요!",
|
||||||
"experimental_settings_title": "실험적기능",
|
"experimental_settings_title": "실험적",
|
||||||
"favorites_page_no_favorites": "즐겨찾기된 미디어를 찾을 수 없습니다",
|
"favorites_page_no_favorites": "즐겨찾기된 항목 없음",
|
||||||
"favorites_page_title": "즐겨찾기",
|
"favorites_page_title": "즐겨찾기",
|
||||||
"haptic_feedback_switch": "햅틱 피드백 활성화",
|
"haptic_feedback_switch": "햅틱 피드백 활성화",
|
||||||
"haptic_feedback_title": "햅틱 피드백",
|
"haptic_feedback_title": "햅틱 피드백",
|
||||||
"home_page_add_to_album_conflicts": "{album} 앨범에 {added} 미디어를 추가했습니다. {failed} 이미 앨범에 있는 항목입니다.",
|
"header_settings_add_header_tip": "헤더 추가",
|
||||||
"home_page_add_to_album_err_local": "아직 앨범에 로컬 미디어를 추가할 수 없으므로 건너뜁니다",
|
"header_settings_field_validator_msg": "값은 비워둘 수 없습니다",
|
||||||
"home_page_add_to_album_success": "{album} 앨범에 {added} 미디어를 추가했습니다. ",
|
"header_settings_header_name_input": "헤더 이름",
|
||||||
"home_page_album_err_partner": "아직 앨범에 파트너 미디어를 추가할 수 없으므로 건너뜁니다",
|
"header_settings_header_value_input": "헤더 값",
|
||||||
"home_page_archive_err_local": "아직 로컬 미디어를 보관할 수 없습니다",
|
"header_settings_page_title": "프록시 헤더",
|
||||||
"home_page_archive_err_partner": "파트너 미디어를 보관할 수 없으므로 건너뛰기",
|
"headers_settings_tile_subtitle": "각 네트워크 요청을 보낼 때 사용할 프록시 헤더를 정의합니다.",
|
||||||
"home_page_building_timeline": "타임라인 생성",
|
"headers_settings_tile_title": "사용자 정의 프록시 헤더",
|
||||||
"home_page_delete_err_partner": "파트너 미디어를 삭제할 수 없으므로 건너뛰기",
|
"home_page_add_to_album_conflicts": "{album} 앨범에 {added} 항목을 추가했습니다. {failed} 이미 앨범에 있는 항목입니다.",
|
||||||
"home_page_delete_remote_err_local": "원격 선택 삭제 시 로컬 미디어, 건너뛰기",
|
"home_page_add_to_album_err_local": "아직 로컬 콘텐츠를 앨범에 추가할 수 없습니다. 건너뜁니다.",
|
||||||
"home_page_favorite_err_local": "아직 로컬 미디어를 즐겨찾기에 추가할 수 없으므로 건너뜁니다",
|
"home_page_add_to_album_success": "{album} 앨범에 {added} 항목을 추가했습니다.",
|
||||||
"home_page_favorite_err_partner": "아직 파트너 미디어를 즐겨찾기에 추가할 수 없습니다.",
|
"home_page_album_err_partner": "아직 앨범에 파트너의 콘텐츠를 추가할 수 없습니다. 건너뜁니다.",
|
||||||
"home_page_first_time_notice": "앱을 처음 사용하는 경우 타임라인이 앨범의 사진과 비디오를 채울 수 있도록 백업대상 앨범을 선택해야 합니다.",
|
"home_page_archive_err_local": "아직 로컬 콘텐츠를 보관할 수 없습니다. 건너뜁니다.",
|
||||||
"home_page_share_err_local": "링크를 통해 로컬 미디어를 공유할 수 없으므로 건너뜁니다",
|
"home_page_archive_err_partner": "파트너의 콘텐츠는 보관할 수 없습니다. 건너뜁니다.",
|
||||||
"home_page_upload_err_limit": "한번에 최대 30개의 미디어만 업로드할 수 있습니다",
|
"home_page_building_timeline": "타임라인 구성 중",
|
||||||
"image_viewer_page_state_provider_download_error": "다운로드 에러",
|
"home_page_delete_err_partner": "파트너의 콘텐츠는 삭제할 수 없습니다. 건너뜁니다.",
|
||||||
"image_viewer_page_state_provider_download_started": "다운로드 시작",
|
"home_page_delete_remote_err_local": "서버에서 삭제된 항목입니다. 건너뜁니다.",
|
||||||
|
"home_page_favorite_err_local": "아직 로컬 콘텐츠를 즐겨찾기에 추가할 수 없습니다. 건너뜁니다.",
|
||||||
|
"home_page_favorite_err_partner": "아직 즐겨찾기에 파트너의 콘텐츠를 추가할 수 없습니다. 건너뜁니다.",
|
||||||
|
"home_page_first_time_notice": "앱을 처음 사용하는 경우 타임라인에 앨범의 사진과 동영상을 채울 수 있도록 백업할 앨범을 선택하세요.",
|
||||||
|
"home_page_share_err_local": "로컬 콘텐츠는 링크를 통해 공유할 수 없습니다. 건너뜁니다.",
|
||||||
|
"home_page_upload_err_limit": "한 번에 최대 30개의 콘텐츠만 업로드할 수 있습니다",
|
||||||
|
"image_viewer_page_state_provider_download_error": "다운로드 오류",
|
||||||
|
"image_viewer_page_state_provider_download_started": "다운로드 시작됨",
|
||||||
"image_viewer_page_state_provider_download_success": "다운로드 완료",
|
"image_viewer_page_state_provider_download_success": "다운로드 완료",
|
||||||
"image_viewer_page_state_provider_share_error": "공유 오류",
|
"image_viewer_page_state_provider_share_error": "공유 오류",
|
||||||
"library_page_albums": "앨범",
|
"library_page_albums": "앨범",
|
||||||
"library_page_archive": "보관",
|
"library_page_archive": "보관",
|
||||||
"library_page_device_albums": "장치의 앨범",
|
"library_page_device_albums": "기기의 앨범",
|
||||||
"library_page_favorites": "즐겨찾기",
|
"library_page_favorites": "즐겨찾기",
|
||||||
"library_page_new_album": "새 앨범",
|
"library_page_new_album": "새 앨범",
|
||||||
"library_page_sharing": "공유",
|
"library_page_sharing": "공유",
|
||||||
"library_page_sort_asset_count": "미디어 수",
|
"library_page_sort_asset_count": "항목 수",
|
||||||
"library_page_sort_created": "최근생성일",
|
"library_page_sort_created": "만든 날짜",
|
||||||
"library_page_sort_last_modified": "마지막 수정",
|
"library_page_sort_last_modified": "마지막 수정",
|
||||||
"library_page_sort_most_oldest_photo": "가장 오래된 사진",
|
"library_page_sort_most_oldest_photo": "오래된 순",
|
||||||
"library_page_sort_most_recent_photo": "가장 최근 사진",
|
"library_page_sort_most_recent_photo": "최신순",
|
||||||
"library_page_sort_title": "앨범 제목",
|
"library_page_sort_title": "앨범 제목",
|
||||||
"location_picker_choose_on_map": "지도에서 선택",
|
"location_picker_choose_on_map": "지도에서 선택",
|
||||||
"location_picker_latitude": "위도",
|
"location_picker_latitude": "위도",
|
||||||
"location_picker_latitude_error": "유효한 위도를 입력하세요",
|
"location_picker_latitude_error": "유효한 위도를 입력하세요.",
|
||||||
"location_picker_latitude_hint": "여기에 위도를 입력하세요",
|
"location_picker_latitude_hint": "이곳에 위도 입력",
|
||||||
"location_picker_longitude": "경도",
|
"location_picker_longitude": "경도",
|
||||||
"location_picker_longitude_error": "유효한 경도를 입력하세요",
|
"location_picker_longitude_error": "유효한 경도를 입력하세요.",
|
||||||
"location_picker_longitude_hint": "여기에 경도를 입력하세요",
|
"location_picker_longitude_hint": "이곳에 경도 입력",
|
||||||
"login_disabled": "로그인이 비활성화되었습니다",
|
"login_disabled": "로그인이 비활성화되었습니다.",
|
||||||
"login_form_api_exception": "API 예외입니다. 서버 URL을 확인한 후 다시 시도하세요",
|
"login_form_api_exception": "API 예외가 발생했습니다. 서버 URL을 확인한 후 다시 시도하세요.",
|
||||||
"login_form_back_button_text": "뒤로",
|
"login_form_back_button_text": "뒤로",
|
||||||
"login_form_button_text": "로그인",
|
"login_form_button_text": "로그인",
|
||||||
"login_form_email_hint": "youremail@email.com",
|
"login_form_email_hint": "youremail@email.com",
|
||||||
"login_form_endpoint_hint": "https://your-server-ip:port/api",
|
"login_form_endpoint_hint": "https://your-server-ip:port/api",
|
||||||
"login_form_endpoint_url": "서버 엔드포인트 URL",
|
"login_form_endpoint_url": "서버 엔드포인트 URL",
|
||||||
"login_form_err_http": "엔드포인트는 http:// 또는 https://로 시작해야 합니다",
|
"login_form_err_http": "엔드포인트는 http:// 또는 https://로 시작해야 합니다.",
|
||||||
"login_form_err_invalid_email": "잘못된 이메일 형식입니다",
|
"login_form_err_invalid_email": "잘못된 이메일입니다.",
|
||||||
"login_form_err_invalid_url": "잘못된 URL 형식입니다",
|
"login_form_err_invalid_url": "잘못된 URL입니다.",
|
||||||
"login_form_err_leading_whitespace": "이메일 앞에 공백문자가 포함되어 있습니다",
|
"login_form_err_leading_whitespace": "이메일 앞에 공백이 있습니다.",
|
||||||
"login_form_err_trailing_whitespace": "이메일 뒤에 공백문자가 포함되어 있습니다",
|
"login_form_err_trailing_whitespace": "이메일 뒤에 공백이 있습니다.",
|
||||||
"login_form_failed_get_oauth_server_config": "OAuth 로그인 오류, 서버 URL을 확인해주세요",
|
"login_form_failed_get_oauth_server_config": "OAuth 로그인 중 문제 발생, 서버 URL을 확인해주세요.",
|
||||||
"login_form_failed_get_oauth_server_disable": "이 서버에서는 OAuth 기능을 사용할 수 없습니다.",
|
"login_form_failed_get_oauth_server_disable": "이 서버는 OAuth 기능을 지원하지 않습니다.",
|
||||||
"login_form_failed_login": "로그인 오류, 서버 URL, 이메일 및 비밀번호를 확인하세요",
|
"login_form_failed_login": "로그인 오류, 서버 URL, 이메일 및 비밀번호를 확인하세요.",
|
||||||
"login_form_handshake_exception": "서버에 핸드셰이크 예외가 발생했습니다. 자체 서명 인증서를 사용하는 경우 설정에서 자체 서명 인증서 지원을 사용 설정합니다",
|
"login_form_handshake_exception": "서버와 통신 중 인증서 예외가 발생했습니다. 자체 서명된 인증서를 사용 중이라면, 설정에서 자체 서명된 인증서 허용을 활성화하세요.",
|
||||||
"login_form_label_email": "이메일",
|
"login_form_label_email": "이메일",
|
||||||
"login_form_label_password": "비밀번호",
|
"login_form_label_password": "비밀번호",
|
||||||
"login_form_next_button": "다음",
|
"login_form_next_button": "다음",
|
||||||
"login_form_password_hint": "비밀번호",
|
"login_form_password_hint": "비밀번호",
|
||||||
"login_form_save_login": "로그인상태 유지",
|
"login_form_save_login": "로그인 상태 유지",
|
||||||
"login_form_server_empty": "서버 URL 입력",
|
"login_form_server_empty": "서버 URL을 입력하세요.",
|
||||||
"login_form_server_error": "서버에 연결할 수 없습니다",
|
"login_form_server_error": "서버에 연결할 수 없습니다.",
|
||||||
"login_password_changed_error": "비밀번호를 업데이트하는 동안 오류가 발생했습니다",
|
"login_password_changed_error": "비밀번호 변경 중 문제가 발생했습니다.",
|
||||||
"login_password_changed_success": "비밀번호 업데이트 성공",
|
"login_password_changed_success": "비밀번호가 변경되었습니다.",
|
||||||
"map_assets_in_bound": "{} 사진",
|
"map_assets_in_bound": "{} 사진",
|
||||||
"map_assets_in_bounds": "{} 사진",
|
"map_assets_in_bounds": "{} 사진",
|
||||||
"map_cannot_get_user_location": "사용자 위치를 가져올 수 없습니다.",
|
"map_cannot_get_user_location": "위치를 불러올 수 없습니다.",
|
||||||
"map_location_dialog_cancel": "아니오",
|
"map_location_dialog_cancel": "아니오",
|
||||||
"map_location_dialog_yes": "예",
|
"map_location_dialog_yes": "예",
|
||||||
"map_location_picker_page_use_location": "이 위치 사용",
|
"map_location_picker_page_use_location": "이 위치 사용",
|
||||||
"map_location_service_disabled_content": "현재 위치의 미디어를 표시하려면 위치 서비스를 활성화해야 합니다. 지금 활성화하시겠습니까?",
|
"map_location_service_disabled_content": "현재 위치의 콘텐츠를 표시하려면 위치 서비스를 활성화해야 합니다. 지금 활성화하시겠습니까?",
|
||||||
"map_location_service_disabled_title": "위치 서비스 비활성화",
|
"map_location_service_disabled_title": "위치 서비스 비활성화됨",
|
||||||
"map_no_assets_in_bounds": "이 영역에 사진이 없습니다",
|
"map_no_assets_in_bounds": "이 영역에 사진 없음",
|
||||||
"map_no_location_permission_content": "현재 위치의 미디어를 표시하려면 위치 권한이 필요합니다. 지금 허용하시겠습니까?",
|
"map_no_location_permission_content": "현재 위치의 콘텐츠를 표시하려면 위치 권한이 필요합니다. 지금 허용하시겠습니까?",
|
||||||
"map_no_location_permission_title": "위치 권한 거부됨",
|
"map_no_location_permission_title": "위치 권한 거부됨",
|
||||||
"map_settings_dark_mode": "다크 모드",
|
"map_settings_dark_mode": "다크 모드",
|
||||||
"map_settings_date_range_option_all": "모두",
|
"map_settings_date_range_option_all": "모두",
|
||||||
"map_settings_date_range_option_day": "지난 24시간",
|
"map_settings_date_range_option_day": "지난 24시간",
|
||||||
"map_settings_date_range_option_days": "지난 {} 일",
|
"map_settings_date_range_option_days": "지난 {}일",
|
||||||
"map_settings_date_range_option_year": "지난 해",
|
"map_settings_date_range_option_year": "지난 해",
|
||||||
"map_settings_date_range_option_years": "지난 {} 년",
|
"map_settings_date_range_option_years": "지난 {}년",
|
||||||
"map_settings_dialog_cancel": "취소",
|
"map_settings_dialog_cancel": "취소",
|
||||||
"map_settings_dialog_save": "저장",
|
"map_settings_dialog_save": "저장",
|
||||||
"map_settings_dialog_title": "지도 설정",
|
"map_settings_dialog_title": "지도 설정",
|
||||||
"map_settings_include_show_archived": "아카이브 포함",
|
"map_settings_include_show_archived": "보관된 항목 포함",
|
||||||
"map_settings_include_show_partners": "파트너 포함",
|
"map_settings_include_show_partners": "파트너 포함",
|
||||||
"map_settings_only_relative_range": "날짜 범위",
|
"map_settings_only_relative_range": "날짜 범위",
|
||||||
"map_settings_only_show_favorites": "즐겨찾기에만 표시",
|
"map_settings_only_show_favorites": "즐겨찾기만 표시",
|
||||||
"map_settings_theme_settings": "지도 테마",
|
"map_settings_theme_settings": "지도 테마",
|
||||||
"map_zoom_to_see_photos": "축소하여 사진 보기",
|
"map_zoom_to_see_photos": "축소하여 사진 보기",
|
||||||
"memories_all_caught_up": "모두 따라잡기",
|
"memories_all_caught_up": "모두 확인함",
|
||||||
"memories_check_back_tomorrow": "더 많은 추억을 위해 내일 다시 확인하세요.",
|
"memories_check_back_tomorrow": "내일 더 많은 추억을 확인하세요.",
|
||||||
"memories_start_over": "다시 시작",
|
"memories_start_over": "다시 보기",
|
||||||
"memories_swipe_to_close": "위로 스와이프하여 닫기",
|
"memories_swipe_to_close": "위로 밀어서 닫기",
|
||||||
|
"memories_year_ago": "1년 전",
|
||||||
|
"memories_years_ago": "{}년 전",
|
||||||
"monthly_title_text_date_format": "y년 M월",
|
"monthly_title_text_date_format": "y년 M월",
|
||||||
"motion_photos_page_title": "모션 사진",
|
"motion_photos_page_title": "모션 포토",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "읽기 전용 미디어의 날짜를 편집할 수 없어 건너뜁니다",
|
"multiselect_grid_edit_date_time_err_read_only": "읽기 전용 콘텐츠의 날짜는 편집할 수 없습니다. 건너뜁니다.",
|
||||||
"multiselect_grid_edit_gps_err_read_only": "읽기 전용 미디어의 위치를 편집할 수 없어 건너뜁니다",
|
"multiselect_grid_edit_gps_err_read_only": "읽기 전용 미디어의 위치는 편집할 수 없습니다. 건너뜁니다.",
|
||||||
"no_assets_to_show": "보여줄 미디어가 없습니다",
|
"no_assets_to_show": "표시할 항목 없음",
|
||||||
"notification_permission_dialog_cancel": "취소",
|
"notification_permission_dialog_cancel": "취소",
|
||||||
"notification_permission_dialog_content": "알림을 활성화하려면 설정으로 이동하여 허용을 선택해주세요.",
|
"notification_permission_dialog_content": "알림을 활성화하려면 설정에서 알림 권한을 허용하세요.",
|
||||||
"notification_permission_dialog_settings": "설정",
|
"notification_permission_dialog_settings": "설정",
|
||||||
"notification_permission_list_tile_content": "알림 활성화 권한허용",
|
"notification_permission_list_tile_content": "알림을 활성화하기 위해 권한을 부여하세요.",
|
||||||
"notification_permission_list_tile_enable_button": "알림 활성화",
|
"notification_permission_list_tile_enable_button": "알림 활성화",
|
||||||
"notification_permission_list_tile_title": "알림 권한",
|
"notification_permission_list_tile_title": "알림 권한",
|
||||||
"partner_list_user_photos": "{user}의 사진",
|
"partner_list_user_photos": "{user}의 사진",
|
||||||
"partner_list_view_all": "모두 보기",
|
"partner_list_view_all": "모두 보기",
|
||||||
"partner_page_add_partner": "파트너 추가",
|
"partner_page_add_partner": "파트너 추가",
|
||||||
"partner_page_empty_message": "사진이 아직 어떤 파트너와도 공유되지 않았습니다",
|
"partner_page_empty_message": "사진이 아직 어떤 파트너와도 공유되지 않았습니다.",
|
||||||
"partner_page_no_more_users": "더 이상 추가할 사용자 없음",
|
"partner_page_no_more_users": "더 이상 추가할 사용자 없음",
|
||||||
"partner_page_partner_add_failed": "파트너 추가에 실패했습니다",
|
"partner_page_partner_add_failed": "파트너를 추가할 수 없습니다.",
|
||||||
"partner_page_select_partner": "파트너 선택",
|
"partner_page_select_partner": "파트너 선택",
|
||||||
"partner_page_shared_to_title": "공유 대상",
|
"partner_page_shared_to_title": "공유 대상",
|
||||||
"partner_page_stop_sharing_content": "더 이상 {}에서 사진에 액세스할 수 없습니다.",
|
"partner_page_stop_sharing_content": "더 이상 당신의 사진에 {}가 접근할 수 없습니다.",
|
||||||
"partner_page_stop_sharing_title": "사진 공유를 중단하시겠습니까?",
|
"partner_page_stop_sharing_title": "사진 공유를 중단하시겠습니까?",
|
||||||
"partner_page_title": "파트너",
|
"partner_page_title": "파트너",
|
||||||
"permission_onboarding_back": "뒤로",
|
"permission_onboarding_back": "뒤로",
|
||||||
"permission_onboarding_continue_anyway": "어쨌든 계속하기",
|
"permission_onboarding_continue_anyway": "무시하고 진행",
|
||||||
"permission_onboarding_get_started": "시작하기",
|
"permission_onboarding_get_started": "시작하기",
|
||||||
"permission_onboarding_go_to_settings": "설정으로 이동",
|
"permission_onboarding_go_to_settings": "설정으로 이동",
|
||||||
"permission_onboarding_grant_permission": "권한 부여",
|
"permission_onboarding_grant_permission": "권한 부여",
|
||||||
"permission_onboarding_log_out": "로그 아웃",
|
"permission_onboarding_log_out": "로그아웃",
|
||||||
"permission_onboarding_permission_denied": "권한이 거부되었습니다. Immich를 사용하려면 설정에서 사진 및 동영상 권한을 부여하세요",
|
"permission_onboarding_permission_denied": "권한이 없습니다. Immich를 사용하려면 설정에서 사진 및 동영상 권한을 부여하세요.",
|
||||||
"permission_onboarding_permission_granted": "승인되었습니다! 모든 준비가 완료되었습니다",
|
"permission_onboarding_permission_granted": "권한이 부여되었습니다! 모든 준비가 완료되었습니다.",
|
||||||
"permission_onboarding_permission_limited": "권한 제한. Immich가 전체 갤러리 컬렉션을 백업하고 관리하도록 하려면 설정에서 사진 및 동영상 권한을 부여하세요",
|
"permission_onboarding_permission_limited": "권한이 없습니다. Immich에서 갤러리 전체 항목을 백업하고 관리하려면 설정에서 사진 및 동영상 권한을 부여하세요.",
|
||||||
"permission_onboarding_request": "Immich는 사진과 동영상을 볼 수 있는 권한을 요구합니다",
|
"permission_onboarding_request": "Immich는 사진 및 동영상 권한이 필요합니다.",
|
||||||
"preferences_settings_title": "기본 설정",
|
"preferences_settings_title": "설정",
|
||||||
"profile_drawer_app_logs": "로그",
|
"profile_drawer_app_logs": "로그",
|
||||||
"profile_drawer_client_out_of_date_major": "모바일 앱이 오래되었습니다. 최신 메이져 버전으로 업데이트하세요.",
|
"profile_drawer_client_out_of_date_major": "모바일 앱이 최신 버전이 아닙니다. 최신 메이저 버전으로 업데이트하세요.",
|
||||||
"profile_drawer_client_out_of_date_minor": "모바일 앱이 구 버전입니다. 최신 마이너 버전으로 업데이트하세요",
|
"profile_drawer_client_out_of_date_minor": "모바일 앱이 최신 버전이 아닙니다. 최신 마이너 버전으로 업데이트하세요.",
|
||||||
"profile_drawer_client_server_up_to_date": "클라이언트와 서버가 최신 상태입니다",
|
"profile_drawer_client_server_up_to_date": "앱과 서버가 최신 버전입니다.",
|
||||||
"profile_drawer_documentation": "문서",
|
"profile_drawer_documentation": "공식 문서",
|
||||||
"profile_drawer_github": "깃허브",
|
"profile_drawer_github": "Github",
|
||||||
"profile_drawer_server_out_of_date_major": "서버 버전이 구 버전입니다. 최신 메이져 버전으로 업데이트하세요",
|
"profile_drawer_server_out_of_date_major": "서버가 최신 버전이 아닙니다. 최신 메이저 버전으로 업데이트하세요.",
|
||||||
"profile_drawer_server_out_of_date_minor": "서버 버전이 구 버전입니다. 최신 마이너 버전으로 업데이트하세요",
|
"profile_drawer_server_out_of_date_minor": "서버가 최신 버전이 아닙니다. 최신 마이너 버전으로 업데이트하세요.",
|
||||||
"profile_drawer_settings": "설정",
|
"profile_drawer_settings": "설정",
|
||||||
"profile_drawer_sign_out": "로그아웃",
|
"profile_drawer_sign_out": "로그아웃",
|
||||||
"profile_drawer_trash": "휴지통",
|
"profile_drawer_trash": "휴지통",
|
||||||
"recently_added_page_title": "최근 추가",
|
"recently_added_page_title": "최근 추가",
|
||||||
"scaffold_body_error_occurred": "오류 발생",
|
"scaffold_body_error_occurred": "문제 발생",
|
||||||
"search_bar_hint": "사진 검색",
|
"search_bar_hint": "사진 검색",
|
||||||
"search_filter_apply": "필터 적용",
|
"search_filter_apply": "필터 적용",
|
||||||
"search_filter_camera_make": "만들기",
|
"search_filter_camera_make": "제조사",
|
||||||
"search_filter_camera_model": "모델",
|
"search_filter_camera_model": "모델",
|
||||||
"search_filter_display_option_archive": "아카이브",
|
"search_filter_display_option_archive": "보관함",
|
||||||
"search_filter_display_option_favorite": "즐겨찾기",
|
"search_filter_display_option_favorite": "즐겨찾기",
|
||||||
"search_filter_display_option_not_in_album": "앨범에 없음",
|
"search_filter_display_option_not_in_album": "어떤 앨범에도 없음",
|
||||||
"search_filter_location_city": "도시",
|
"search_filter_location_city": "도시",
|
||||||
"search_filter_location_country": "국가",
|
"search_filter_location_country": "국가",
|
||||||
"search_filter_location_state": "상태",
|
"search_filter_location_state": "지역",
|
||||||
"search_filter_media_type_all": "전체",
|
"search_filter_media_type_all": "전체",
|
||||||
"search_filter_media_type_image": "이미지",
|
"search_filter_media_type_image": "이미지",
|
||||||
"search_filter_media_type_video": "비디오",
|
"search_filter_media_type_video": "동영상",
|
||||||
"search_page_categories": "카테고리",
|
"search_page_categories": "분류",
|
||||||
"search_page_favorites": "즐겨찾기",
|
"search_page_favorites": "즐겨찾기",
|
||||||
"search_page_motion_photos": "모션 사진",
|
"search_page_motion_photos": "모션 포토",
|
||||||
"search_page_no_objects": "발견된 사물이\n없습니다",
|
"search_page_no_objects": "사물 정보가 없습니다.",
|
||||||
"search_page_no_places": "발견된 장소가\n없습니다",
|
"search_page_no_places": "장소 정보가 없습니다.",
|
||||||
"search_page_people": "사람",
|
"search_page_people": "인물",
|
||||||
"search_page_person_add_name_dialog_cancel": "취소",
|
"search_page_person_add_name_dialog_cancel": "취소",
|
||||||
"search_page_person_add_name_dialog_hint": "이름",
|
"search_page_person_add_name_dialog_hint": "이름",
|
||||||
"search_page_person_add_name_dialog_save": "저장",
|
"search_page_person_add_name_dialog_save": "저장",
|
||||||
"search_page_person_add_name_dialog_title": "이름 추가",
|
"search_page_person_add_name_dialog_title": "이름 추가",
|
||||||
"search_page_person_add_name_subtitle": "검색을 통해 이름으로 빠르게 찾기",
|
"search_page_person_add_name_subtitle": "검색을 통해 이름으로 빠르게 찾기",
|
||||||
"search_page_person_add_name_title": "이름 추가",
|
"search_page_person_add_name_title": "이름 추가",
|
||||||
"search_page_person_edit_name": "이름 수정",
|
"search_page_person_edit_name": "이름 편집",
|
||||||
"search_page_places": "장소",
|
"search_page_places": "장소",
|
||||||
"search_page_recently_added": "최근 추가",
|
"search_page_recently_added": "최근 추가",
|
||||||
"search_page_screenshots": "스크린샷",
|
"search_page_screenshots": "스크린샷",
|
||||||
"search_page_selfies": "셀카",
|
"search_page_selfies": "셀피",
|
||||||
"search_page_things": "사물",
|
"search_page_things": "사물",
|
||||||
"search_page_videos": "동영상",
|
"search_page_videos": "동영상",
|
||||||
"search_page_view_all_button": "모두 보기",
|
"search_page_view_all_button": "모두 보기",
|
||||||
"search_page_your_activity": "내 활동",
|
"search_page_your_activity": "나의 활동",
|
||||||
"search_page_your_map": "내 지도",
|
"search_page_your_map": "나의 지도",
|
||||||
"search_result_page_new_search_hint": "새 검색",
|
"search_result_page_new_search_hint": "새 검색",
|
||||||
"search_suggestion_list_smart_search_hint_1": "스마트 검색은 기본적으로 활성화되어 있으며, 메타데이터를 검색하려면 다음 구문을 사용합니다",
|
"search_suggestion_list_smart_search_hint_1": "스마트 검색이 기본적으로 활성화되어 있습니다. 메타데이터로 검색하려면 다음 구문을 사용하세요.",
|
||||||
"search_suggestion_list_smart_search_hint_2": "m:your-search-term",
|
"search_suggestion_list_smart_search_hint_2": "m:your-search-term",
|
||||||
"select_additional_user_for_sharing_page_suggestions": "초대 가능한 사용자 제안",
|
"select_additional_user_for_sharing_page_suggestions": "추천",
|
||||||
"select_user_for_sharing_page_err_album": "앨범 생성 실패",
|
"select_user_for_sharing_page_err_album": "앨범을 생성하지 못했습니다.",
|
||||||
"select_user_for_sharing_page_share_suggestions": "초대 가능한 사용자 제안",
|
"select_user_for_sharing_page_share_suggestions": "추천",
|
||||||
"server_info_box_app_version": "앱 버전",
|
"server_info_box_app_version": "앱 버전",
|
||||||
"server_info_box_latest_release": "마지막 버전",
|
"server_info_box_latest_release": "최신 버전",
|
||||||
"server_info_box_server_url": "서버 URL",
|
"server_info_box_server_url": "서버 URL",
|
||||||
"server_info_box_server_version": "서버 버전",
|
"server_info_box_server_version": "서버 버전",
|
||||||
"setting_image_viewer_help": "상세뷰어는 먼저 작은 썸네일을 불러온 다음 중간크기 미리보기를 불러오고(활성화된 경우) 마지막으로 원본을 불러옵니다(활성화된 경우).",
|
"setting_image_viewer_help": "상세 보기는 먼저 작은 크기의 섬네일을 불러오며, 활성화된 경우 중간 크기의 이미지와 원본을 불러옵니다.",
|
||||||
"setting_image_viewer_original_subtitle": "원본 해상도 이미지(고화질)를 로드하려면 활성화합니다. 데이터 사용량을 줄이려면 비활성화합니다.",
|
"setting_image_viewer_original_subtitle": "원본 해상도 이미지(고화질)를 로드합니다. 데이터 사용량을 줄이려면 비활성화하세요.",
|
||||||
"setting_image_viewer_original_title": "원본 이미지 불러오기",
|
"setting_image_viewer_original_title": "원본 이미지 선호",
|
||||||
"setting_image_viewer_preview_subtitle": "중간 해상도 이미지를 로드하려면 활성화합니다. 원본을 직접 로드하거나 썸네일만 사용하려면 비활성화 하세요.",
|
"setting_image_viewer_preview_subtitle": "중간 크기의 이미지를 불러오려면 활성화하세요. 항상 원본을 불러오거나 섬네일만 불러오려면 비활성화하세요.",
|
||||||
"setting_image_viewer_preview_title": "미리보기 이미지 불러오기",
|
"setting_image_viewer_preview_title": "미리 보기 이미지 불러오기",
|
||||||
"setting_image_viewer_title": "이미지",
|
"setting_image_viewer_title": "이미지",
|
||||||
"setting_languages_apply": "적용",
|
"setting_languages_apply": "적용",
|
||||||
"setting_languages_title": "언어",
|
"setting_languages_title": "언어",
|
||||||
@@ -399,74 +410,74 @@
|
|||||||
"setting_notifications_notify_immediately": "즉시",
|
"setting_notifications_notify_immediately": "즉시",
|
||||||
"setting_notifications_notify_minutes": "{}분 뒤",
|
"setting_notifications_notify_minutes": "{}분 뒤",
|
||||||
"setting_notifications_notify_never": "알리지 않음",
|
"setting_notifications_notify_never": "알리지 않음",
|
||||||
"setting_notifications_notify_seconds": "{} 초",
|
"setting_notifications_notify_seconds": "{}초",
|
||||||
"setting_notifications_single_progress_subtitle": "미디어별 상세 진행률 표시",
|
"setting_notifications_single_progress_subtitle": "각 항목의 세부 업로드 정보 표시",
|
||||||
"setting_notifications_single_progress_title": "백그라운드 작업 세부 진행률 표시",
|
"setting_notifications_single_progress_title": "백그라운드 작업의 세부 진행률 표시",
|
||||||
"setting_notifications_subtitle": "알림 기본 설정 조정",
|
"setting_notifications_subtitle": "알림 기본 설정 조정",
|
||||||
"setting_notifications_title": "알림",
|
"setting_notifications_title": "알림",
|
||||||
"setting_notifications_total_progress_subtitle": "전체 업로드 진행률(완료/전체)",
|
"setting_notifications_total_progress_subtitle": "전체 업로드 진행률 (완료/전체)",
|
||||||
"setting_notifications_total_progress_title": "백그라운드 작업 전체 진행률 표시",
|
"setting_notifications_total_progress_title": "백그라운드 작업의 전체 진행률 표시",
|
||||||
"setting_pages_app_bar_settings": "설정",
|
"setting_pages_app_bar_settings": "설정",
|
||||||
"settings_require_restart": "설정을 적용하려면 Immich를 다시 시작하세요.",
|
"settings_require_restart": "설정을 적용하려면 Immich를 다시 시작하세요.",
|
||||||
"setting_video_viewer_looping_subtitle": "상세 뷰어에서 비디오를 자동으로 반복하도록 활성화합니다.",
|
"setting_video_viewer_looping_subtitle": "상세 보기에서 동영상을 자동으로 반복합니다.",
|
||||||
"setting_video_viewer_looping_title": "반복",
|
"setting_video_viewer_looping_title": "반복",
|
||||||
"setting_video_viewer_title": "비디오",
|
"setting_video_viewer_title": "동영상",
|
||||||
"share_add": "추가",
|
"share_add": "추가",
|
||||||
"share_add_photos": "사진 추가",
|
"share_add_photos": "사진 추가",
|
||||||
"share_add_title": "새 앨범제목",
|
"share_add_title": "앨범 제목 입력",
|
||||||
"share_assets_selected": "{} 선택됨",
|
"share_assets_selected": "{}개 선택됨",
|
||||||
"share_create_album": "앨범 만들기",
|
"share_create_album": "앨범 생성",
|
||||||
"shared_album_activities_input_disable": "댓글이 비활성화되었습니다.",
|
"shared_album_activities_input_disable": "댓글 기능이 비활성화됨",
|
||||||
"shared_album_activities_input_hint": "말하기",
|
"shared_album_activities_input_hint": "무엇이든 말해보세요",
|
||||||
"shared_album_activity_remove_content": "이 활동을 삭제하시겠습니까?",
|
"shared_album_activity_remove_content": "이 활동을 삭제하시겠습니까?",
|
||||||
"shared_album_activity_remove_title": "활동 삭제",
|
"shared_album_activity_remove_title": "활동 삭제",
|
||||||
"shared_album_activity_setting_subtitle": "다른 사람이 응답하도록 허용",
|
"shared_album_activity_setting_subtitle": "다른 사람들의 반응 허용",
|
||||||
"shared_album_activity_setting_title": "댓글 및 좋아요",
|
"shared_album_activity_setting_title": "댓글 & 좋아요",
|
||||||
"shared_album_section_people_action_error": "앨범에서 나가기/제거 중 오류 발생",
|
"shared_album_section_people_action_error": "앨범에서 나가기/제거 중 문제가 발생했습니다.",
|
||||||
"shared_album_section_people_action_leave": "앨범에서 사용자 제거",
|
"shared_album_section_people_action_leave": "앨범에서 사용자 제거",
|
||||||
"shared_album_section_people_action_remove_user": "앨범에서 사용자 제거",
|
"shared_album_section_people_action_remove_user": "앨범에서 사용자 제거",
|
||||||
"shared_album_section_people_owner_label": "소유자",
|
"shared_album_section_people_owner_label": "소유자",
|
||||||
"shared_album_section_people_title": "사람",
|
"shared_album_section_people_title": "인물",
|
||||||
"share_dialog_preparing": "준비중...",
|
"share_dialog_preparing": "준비 중...",
|
||||||
"shared_link_app_bar_title": "공유 링크",
|
"shared_link_app_bar_title": "공유 링크",
|
||||||
"shared_link_clipboard_copied_massage": "클립보드에 복사",
|
"shared_link_clipboard_copied_massage": "클립보드에 복사되었습니다.",
|
||||||
"shared_link_clipboard_text": "링크: {}\n패스워드: {}",
|
"shared_link_clipboard_text": "링크: {}\n비밀번호: {}",
|
||||||
"shared_link_create_app_bar_title": "공유할 링크 만들기",
|
"shared_link_create_app_bar_title": "공유 링크 생성",
|
||||||
"shared_link_create_error": "공유 링크 생성 중 오류 발생",
|
"shared_link_create_error": "공유 링크 생성 중 문제가 발생했습니다.",
|
||||||
"shared_link_create_info": "링크를 가진 모든 사람이 선택한 사진을 볼 수 있도록 합니다",
|
"shared_link_create_info": "링크가 있는 모든 사람이 선택한 사진을 볼 수 있게 하기",
|
||||||
"shared_link_create_submit_button": "링크 만들기",
|
"shared_link_create_submit_button": "링크 생성",
|
||||||
"shared_link_edit_allow_download": "공용 사용자의 다운로드 허용",
|
"shared_link_edit_allow_download": "모든 사용자의 다운로드 허용",
|
||||||
"shared_link_edit_allow_upload": "공용 사용자의 업로드 허용",
|
"shared_link_edit_allow_upload": "모든 사용자의 업로드 허용",
|
||||||
"shared_link_edit_app_bar_title": "링크 수정",
|
"shared_link_edit_app_bar_title": "링크 수정",
|
||||||
"shared_link_edit_change_expiry": "만료 시간 변경",
|
"shared_link_edit_change_expiry": "만료 시간 변경",
|
||||||
"shared_link_edit_description": "설명",
|
"shared_link_edit_description": "설명",
|
||||||
"shared_link_edit_description_hint": "공유 설명 입력",
|
"shared_link_edit_description_hint": "공유 링크 설명 입력",
|
||||||
"shared_link_edit_expire_after": "만료 후",
|
"shared_link_edit_expire_after": "다음 이후 만료",
|
||||||
"shared_link_edit_expire_after_option_day": "1 일",
|
"shared_link_edit_expire_after_option_day": "1일",
|
||||||
"shared_link_edit_expire_after_option_days": "{} 일",
|
"shared_link_edit_expire_after_option_days": "{}일",
|
||||||
"shared_link_edit_expire_after_option_hour": "1 시간",
|
"shared_link_edit_expire_after_option_hour": "1시간",
|
||||||
"shared_link_edit_expire_after_option_hours": "{} 시간",
|
"shared_link_edit_expire_after_option_hours": "{}시간",
|
||||||
"shared_link_edit_expire_after_option_minute": "1 분",
|
"shared_link_edit_expire_after_option_minute": "1분",
|
||||||
"shared_link_edit_expire_after_option_minutes": "{} 분",
|
"shared_link_edit_expire_after_option_minutes": "{}분",
|
||||||
"shared_link_edit_expire_after_option_months": "{} 개월",
|
"shared_link_edit_expire_after_option_months": "{}개월",
|
||||||
"shared_link_edit_expire_after_option_never": "절대로",
|
"shared_link_edit_expire_after_option_never": "만료되지 않음",
|
||||||
"shared_link_edit_expire_after_option_year": "{} 년",
|
"shared_link_edit_expire_after_option_year": "{}년",
|
||||||
"shared_link_edit_password": "비밀번호",
|
"shared_link_edit_password": "비밀번호",
|
||||||
"shared_link_edit_password_hint": "공유 비밀번호 입력",
|
"shared_link_edit_password_hint": "공유 비밀번호 입력",
|
||||||
"shared_link_edit_show_meta": "메타데이터 표시",
|
"shared_link_edit_show_meta": "메타데이터 표시",
|
||||||
"shared_link_edit_submit_button": "링크 업데이트",
|
"shared_link_edit_submit_button": "링크 업데이트",
|
||||||
"shared_link_empty": "공유 링크가 없습니다",
|
"shared_link_empty": "생성한 공유 링크가 없습니다.",
|
||||||
"shared_link_error_server_url_fetch": "서버 URL을 가져올 수 없습니다",
|
"shared_link_error_server_url_fetch": "서버 URL을 불러올 수 없습니다.",
|
||||||
"shared_link_expired": "만료됨",
|
"shared_link_expired": "만료됨",
|
||||||
"shared_link_expires_day": "{} 일 후 만료됩니다",
|
"shared_link_expires_day": "{}일 후 만료",
|
||||||
"shared_link_expires_days": "{} 일 후에 만료됩니다",
|
"shared_link_expires_days": "{}일 후 만료",
|
||||||
"shared_link_expires_hour": "{} 시간 후 만료됩니다",
|
"shared_link_expires_hour": "{}시간 후 만료",
|
||||||
"shared_link_expires_hours": "{} 시간 후에 만료됩니다",
|
"shared_link_expires_hours": "{}시간 후 만료",
|
||||||
"shared_link_expires_minute": "{} 분 후 만료됩니다",
|
"shared_link_expires_minute": "{}분 후 만료",
|
||||||
"shared_link_expires_minutes": "{} 분 후 만료",
|
"shared_link_expires_minutes": "{}분 후 만료",
|
||||||
"shared_link_expires_never": "만료 ∞",
|
"shared_link_expires_never": "만료되지 않음",
|
||||||
"shared_link_expires_second": "{} 초 후 만료됩니다",
|
"shared_link_expires_second": "{}초 후 만료",
|
||||||
"shared_link_expires_seconds": "{} 초 후 만료",
|
"shared_link_expires_seconds": "{}초 후 만료",
|
||||||
"shared_link_individual_shared": "개인 공유",
|
"shared_link_individual_shared": "개인 공유",
|
||||||
"shared_link_info_chip_download": "다운로드",
|
"shared_link_info_chip_download": "다운로드",
|
||||||
"shared_link_info_chip_metadata": "EXIF",
|
"shared_link_info_chip_metadata": "EXIF",
|
||||||
@@ -475,50 +486,50 @@
|
|||||||
"shared_link_public_album": "공개 앨범",
|
"shared_link_public_album": "공개 앨범",
|
||||||
"share_done": "완료",
|
"share_done": "완료",
|
||||||
"share_invite": "앨범에 초대",
|
"share_invite": "앨범에 초대",
|
||||||
"sharing_page_album": "공유앨범",
|
"sharing_page_album": "공유 앨범",
|
||||||
"sharing_page_description": "공유앨범을 만들어 다른 사용자들과 사진 및 비디오를 공유합니다.",
|
"sharing_page_description": "공유 앨범을 만들어 네트워크에 있는 사람들과 사진 및 동영상을 공유하세요",
|
||||||
"sharing_page_empty_list": "공유앨범 없음",
|
"sharing_page_empty_list": "공유 앨범 없음",
|
||||||
"sharing_silver_appbar_create_shared_album": "공유앨범 만들기",
|
"sharing_silver_appbar_create_shared_album": "공유 앨범 생성",
|
||||||
"sharing_silver_appbar_shared_links": "공유 링크",
|
"sharing_silver_appbar_shared_links": "공유 링크",
|
||||||
"sharing_silver_appbar_share_partner": "파트너와 공유",
|
"sharing_silver_appbar_share_partner": "파트너와 공유",
|
||||||
"tab_controller_nav_library": "라이브러리",
|
"tab_controller_nav_library": "라이브러리",
|
||||||
"tab_controller_nav_photos": "사진",
|
"tab_controller_nav_photos": "사진",
|
||||||
"tab_controller_nav_search": "검색",
|
"tab_controller_nav_search": "검색",
|
||||||
"tab_controller_nav_sharing": "공유",
|
"tab_controller_nav_sharing": "공유",
|
||||||
"theme_setting_asset_list_storage_indicator_title": "미디어 타일에 스토리지 싱크여부 표시",
|
"theme_setting_asset_list_storage_indicator_title": "항목에 스토리지 상태 표시",
|
||||||
"theme_setting_asset_list_tiles_per_row_title": "한 줄에 표시할 미디어 수 ({})",
|
"theme_setting_asset_list_tiles_per_row_title": "한 줄에 표시할 항목 수 ({})",
|
||||||
"theme_setting_dark_mode_switch": "다크모드",
|
"theme_setting_dark_mode_switch": "다크 모드",
|
||||||
"theme_setting_image_viewer_quality_subtitle": "디테일 이미지 뷰어 품질 조정",
|
"theme_setting_image_viewer_quality_subtitle": "상세 보기 이미지 품질 조정",
|
||||||
"theme_setting_image_viewer_quality_title": "이미지 뷰어 품질",
|
"theme_setting_image_viewer_quality_title": "이미지 보기 품질",
|
||||||
"theme_setting_system_theme_switch": "자동(시스템 설정에 따름)",
|
"theme_setting_system_theme_switch": "자동 (시스템 설정)",
|
||||||
"theme_setting_theme_subtitle": "앱테마 선택",
|
"theme_setting_theme_subtitle": "앱 테마 선택",
|
||||||
"theme_setting_theme_title": "테마",
|
"theme_setting_theme_title": "테마",
|
||||||
"theme_setting_three_stage_loading_subtitle": "이 기능은 로딩 성능을 향상시킬 수 있지만 훨씬 더 많은 데이터를 사용합니다.",
|
"theme_setting_three_stage_loading_subtitle": "이 기능은 앱의 로드 성능을 향상시킬 수 있지만 더 많은 데이터를 사용합니다.",
|
||||||
"theme_setting_three_stage_loading_title": "3단계 로딩 활성화",
|
"theme_setting_three_stage_loading_title": "3단계 로드 활성화",
|
||||||
"translated_text_options": "옵션",
|
"translated_text_options": "옵션",
|
||||||
"trash_page_delete": "삭제",
|
"trash_page_delete": "삭제",
|
||||||
"trash_page_delete_all": "모두 삭제",
|
"trash_page_delete_all": "모두 삭제",
|
||||||
"trash_page_empty_trash_btn": "휴지통 비우기",
|
"trash_page_empty_trash_btn": "휴지통 비우기",
|
||||||
"trash_page_empty_trash_dialog_content": "휴지통에 버린 미디어를 비우고 싶으신가요? 이 항목들은 Immich에서 영구적으로 삭제됩니다",
|
"trash_page_empty_trash_dialog_content": "휴지통을 비우시겠습니까? 해당 항목들이 Immich에서 영구적으로 삭제되며 되돌릴 수 없습니다.",
|
||||||
"trash_page_empty_trash_dialog_ok": "확인",
|
"trash_page_empty_trash_dialog_ok": "확인",
|
||||||
"trash_page_info": "휴지통에 버린 항목은 {}일 후에 영구 삭제됩니다",
|
"trash_page_info": "휴지통으로 이동된 항목은 {}일 후 영구적으로 삭제됩니다.",
|
||||||
"trash_page_no_assets": "휴지통에 버려진 미디어 없음",
|
"trash_page_no_assets": "휴지통이 비어 있음",
|
||||||
"trash_page_restore": "복원",
|
"trash_page_restore": "복원",
|
||||||
"trash_page_restore_all": "모두 복원",
|
"trash_page_restore_all": "모두 복원",
|
||||||
"trash_page_select_assets_btn": "미디어 선택",
|
"trash_page_select_assets_btn": "항목 선택",
|
||||||
"trash_page_select_btn": "선택",
|
"trash_page_select_btn": "선택",
|
||||||
"trash_page_title": "휴지통 ({})",
|
"trash_page_title": "휴지통 ({})",
|
||||||
"upload_dialog_cancel": "취소",
|
"upload_dialog_cancel": "취소",
|
||||||
"upload_dialog_info": "선택한 미디어를 서버에 백업하시겠습니까?",
|
"upload_dialog_info": "선택한 항목을 서버에 백업하시겠습니까?",
|
||||||
"upload_dialog_ok": "업로드",
|
"upload_dialog_ok": "업로드",
|
||||||
"upload_dialog_title": "미디어 업로드",
|
"upload_dialog_title": "콘텐츠 업로드",
|
||||||
"version_announcement_overlay_ack": "승인",
|
"version_announcement_overlay_ack": "확인",
|
||||||
"version_announcement_overlay_release_notes": "릴리스 정보",
|
"version_announcement_overlay_release_notes": "릴리스 정보",
|
||||||
"version_announcement_overlay_text_1": "안녕하세요!",
|
"version_announcement_overlay_text_1": "안녕하세요,",
|
||||||
"version_announcement_overlay_text_2": "앱에 새로운 업데이트가 있습니다!",
|
"version_announcement_overlay_text_2": "새 업데이트가 있습니다.",
|
||||||
"version_announcement_overlay_text_3": "특히 WatchTower 또는 서버 응용 프로그램 자동 업데이트를 처리하는 메커니즘을 사용하는 경우 잘못된 구성을 방지하기 위해 docker-compose 및 .env 설정이 최신 상태인지 확인하세요.",
|
"version_announcement_overlay_text_3": "WatchTower 또는 서버 애플리케이션의 자동 업데이트 기능을 사용하는 경우 잘못된 구성을 방지하기 위해 docker-compose 및 .env 설정이 최신 상태인지 확인하세요.",
|
||||||
"version_announcement_overlay_title": "새 서버 버전 사용 가능 \uD83C\uDF89",
|
"version_announcement_overlay_title": "새 서버 버전 사용 가능 \uD83C\uDF89",
|
||||||
"viewer_remove_from_stack": "합치기에서 제거",
|
"viewer_remove_from_stack": "스택에서 제거",
|
||||||
"viewer_stack_use_as_main_asset": "메인 미디어로 사용",
|
"viewer_stack_use_as_main_asset": "대표 사진으로 설정",
|
||||||
"viewer_unstack": "풀기"
|
"viewer_unstack": "스택 해제"
|
||||||
}
|
}
|
||||||
@@ -9,6 +9,8 @@
|
|||||||
"advanced_settings_log_level_title": "Log level: {}",
|
"advanced_settings_log_level_title": "Log level: {}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "Some devices are painfully slow to load thumbnails from assets on the device. Activate this setting to load remote images instead.",
|
"advanced_settings_prefer_remote_subtitle": "Some devices are painfully slow to load thumbnails from assets on the device. Activate this setting to load remote images instead.",
|
||||||
"advanced_settings_prefer_remote_title": "Prefer remote images",
|
"advanced_settings_prefer_remote_title": "Prefer remote images",
|
||||||
|
"advanced_settings_proxy_headers_subtitle": "Define proxy headers Immich should send with each network request",
|
||||||
|
"advanced_settings_proxy_headers_title": "Proxy Headers",
|
||||||
"advanced_settings_self_signed_ssl_subtitle": "Skips SSL certificate verification for the server endpoint. Required for self-signed certificates.",
|
"advanced_settings_self_signed_ssl_subtitle": "Skips SSL certificate verification for the server endpoint. Required for self-signed certificates.",
|
||||||
"advanced_settings_self_signed_ssl_title": "Allow self-signed SSL certificates",
|
"advanced_settings_self_signed_ssl_title": "Allow self-signed SSL certificates",
|
||||||
"advanced_settings_tile_subtitle": "Advanced user's settings",
|
"advanced_settings_tile_subtitle": "Advanced user's settings",
|
||||||
@@ -203,6 +205,13 @@
|
|||||||
"favorites_page_title": "Favorites",
|
"favorites_page_title": "Favorites",
|
||||||
"haptic_feedback_switch": "Enable haptic feedback",
|
"haptic_feedback_switch": "Enable haptic feedback",
|
||||||
"haptic_feedback_title": "Haptic Feedback",
|
"haptic_feedback_title": "Haptic Feedback",
|
||||||
|
"header_settings_add_header_tip": "Add Header",
|
||||||
|
"header_settings_field_validator_msg": "Value cannot be empty",
|
||||||
|
"header_settings_header_name_input": "Header name",
|
||||||
|
"header_settings_header_value_input": "Header value",
|
||||||
|
"header_settings_page_title": "Proxy Headers",
|
||||||
|
"headers_settings_tile_subtitle": "Define proxy headers the app should send with each network request",
|
||||||
|
"headers_settings_tile_title": "Custom proxy headers",
|
||||||
"home_page_add_to_album_conflicts": "Added {added} assets to album {album}. {failed} assets are already in the album.",
|
"home_page_add_to_album_conflicts": "Added {added} assets to album {album}. {failed} assets are already in the album.",
|
||||||
"home_page_add_to_album_err_local": "Can not add local assets to albums yet, skipping",
|
"home_page_add_to_album_err_local": "Can not add local assets to albums yet, skipping",
|
||||||
"home_page_add_to_album_success": "Added {added} assets to album {album}.",
|
"home_page_add_to_album_success": "Added {added} assets to album {album}.",
|
||||||
@@ -295,6 +304,8 @@
|
|||||||
"memories_check_back_tomorrow": "Check back tomorrow for more memories",
|
"memories_check_back_tomorrow": "Check back tomorrow for more memories",
|
||||||
"memories_start_over": "Start Over",
|
"memories_start_over": "Start Over",
|
||||||
"memories_swipe_to_close": "Swipe up to close",
|
"memories_swipe_to_close": "Swipe up to close",
|
||||||
|
"memories_year_ago": "A year ago",
|
||||||
|
"memories_years_ago": "{} years ago",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "Motion Photos",
|
"motion_photos_page_title": "Motion Photos",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
"advanced_settings_log_level_title": "Žurnalēšanas līmenis: {}",
|
"advanced_settings_log_level_title": "Žurnalēšanas līmenis: {}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "Dažās ierīcēs sīktēli no ierīcē esošajiem resursiem tiek ielādēti ļoti lēni. Aktivizējiet šo iestatījumu, lai tā vietā ielādētu attālus attēlus.",
|
"advanced_settings_prefer_remote_subtitle": "Dažās ierīcēs sīktēli no ierīcē esošajiem resursiem tiek ielādēti ļoti lēni. Aktivizējiet šo iestatījumu, lai tā vietā ielādētu attālus attēlus.",
|
||||||
"advanced_settings_prefer_remote_title": "Dot priekšroku attāliem attēliem",
|
"advanced_settings_prefer_remote_title": "Dot priekšroku attāliem attēliem",
|
||||||
|
"advanced_settings_proxy_headers_subtitle": "Define proxy headers Immich should send with each network request",
|
||||||
|
"advanced_settings_proxy_headers_title": "Proxy Headers",
|
||||||
"advanced_settings_self_signed_ssl_subtitle": "Izlaiž servera galapunkta SSL sertifikātu verifikāciju. Nepieciešams pašparakstītajiem sertifikātiem.",
|
"advanced_settings_self_signed_ssl_subtitle": "Izlaiž servera galapunkta SSL sertifikātu verifikāciju. Nepieciešams pašparakstītajiem sertifikātiem.",
|
||||||
"advanced_settings_self_signed_ssl_title": "Atļaut pašparakstītus SSL sertifikātus",
|
"advanced_settings_self_signed_ssl_title": "Atļaut pašparakstītus SSL sertifikātus",
|
||||||
"advanced_settings_tile_subtitle": "Lietotāja papildu iestatījumi",
|
"advanced_settings_tile_subtitle": "Lietotāja papildu iestatījumi",
|
||||||
@@ -203,6 +205,13 @@
|
|||||||
"favorites_page_title": "Izlase",
|
"favorites_page_title": "Izlase",
|
||||||
"haptic_feedback_switch": "Iestatīt haptisku reakciju",
|
"haptic_feedback_switch": "Iestatīt haptisku reakciju",
|
||||||
"haptic_feedback_title": "Haptiska Reakcija",
|
"haptic_feedback_title": "Haptiska Reakcija",
|
||||||
|
"header_settings_add_header_tip": "Add Header",
|
||||||
|
"header_settings_field_validator_msg": "Value cannot be empty",
|
||||||
|
"header_settings_header_name_input": "Header name",
|
||||||
|
"header_settings_header_value_input": "Header value",
|
||||||
|
"header_settings_page_title": "Proxy Headers",
|
||||||
|
"headers_settings_tile_subtitle": "Define proxy headers the app should send with each network request",
|
||||||
|
"headers_settings_tile_title": "Custom proxy headers",
|
||||||
"home_page_add_to_album_conflicts": "Pievienoja {added} aktīvus albumam {album}. {failed} aktīvi jau ir albumā.",
|
"home_page_add_to_album_conflicts": "Pievienoja {added} aktīvus albumam {album}. {failed} aktīvi jau ir albumā.",
|
||||||
"home_page_add_to_album_err_local": "Albumiem vēl nevar pievienot lokālos aktīvus, notiek izlaišana",
|
"home_page_add_to_album_err_local": "Albumiem vēl nevar pievienot lokālos aktīvus, notiek izlaišana",
|
||||||
"home_page_add_to_album_success": "Pievienoja {added} aktīvus albumam {album}.",
|
"home_page_add_to_album_success": "Pievienoja {added} aktīvus albumam {album}.",
|
||||||
@@ -295,6 +304,8 @@
|
|||||||
"memories_check_back_tomorrow": "Priekš vairāk atmiņām atgriezieties rītdien.",
|
"memories_check_back_tomorrow": "Priekš vairāk atmiņām atgriezieties rītdien.",
|
||||||
"memories_start_over": "Sākt no jauna",
|
"memories_start_over": "Sākt no jauna",
|
||||||
"memories_swipe_to_close": "Pavelciet uz augšu, lai aizvērtu",
|
"memories_swipe_to_close": "Pavelciet uz augšu, lai aizvērtu",
|
||||||
|
"memories_year_ago": "A year ago",
|
||||||
|
"memories_years_ago": "{} years ago",
|
||||||
"monthly_title_text_date_format": "MMMM g",
|
"monthly_title_text_date_format": "MMMM g",
|
||||||
"motion_photos_page_title": "Kustību Fotoattēli",
|
"motion_photos_page_title": "Kustību Fotoattēli",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "Nevar rediģēt read only aktīva(-u) datumu, notiek izlaišana",
|
"multiselect_grid_edit_date_time_err_read_only": "Nevar rediģēt read only aktīva(-u) datumu, notiek izlaišana",
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
"advanced_settings_log_level_title": "Log level: {}",
|
"advanced_settings_log_level_title": "Log level: {}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "Some devices are painfully slow to load thumbnails from assets on the device. Activate this setting to load remote images instead.",
|
"advanced_settings_prefer_remote_subtitle": "Some devices are painfully slow to load thumbnails from assets on the device. Activate this setting to load remote images instead.",
|
||||||
"advanced_settings_prefer_remote_title": "Prefer remote images",
|
"advanced_settings_prefer_remote_title": "Prefer remote images",
|
||||||
|
"advanced_settings_proxy_headers_subtitle": "Define proxy headers Immich should send with each network request",
|
||||||
|
"advanced_settings_proxy_headers_title": "Proxy Headers",
|
||||||
"advanced_settings_self_signed_ssl_subtitle": "Skips SSL certificate verification for the server endpoint. Required for self-signed certificates.",
|
"advanced_settings_self_signed_ssl_subtitle": "Skips SSL certificate verification for the server endpoint. Required for self-signed certificates.",
|
||||||
"advanced_settings_self_signed_ssl_title": "Allow self-signed SSL certificates",
|
"advanced_settings_self_signed_ssl_title": "Allow self-signed SSL certificates",
|
||||||
"advanced_settings_tile_subtitle": "Advanced user's settings",
|
"advanced_settings_tile_subtitle": "Advanced user's settings",
|
||||||
@@ -203,6 +205,13 @@
|
|||||||
"favorites_page_title": "Favorites",
|
"favorites_page_title": "Favorites",
|
||||||
"haptic_feedback_switch": "Enable haptic feedback",
|
"haptic_feedback_switch": "Enable haptic feedback",
|
||||||
"haptic_feedback_title": "Haptic Feedback",
|
"haptic_feedback_title": "Haptic Feedback",
|
||||||
|
"header_settings_add_header_tip": "Add Header",
|
||||||
|
"header_settings_field_validator_msg": "Value cannot be empty",
|
||||||
|
"header_settings_header_name_input": "Header name",
|
||||||
|
"header_settings_header_value_input": "Header value",
|
||||||
|
"header_settings_page_title": "Proxy Headers",
|
||||||
|
"headers_settings_tile_subtitle": "Define proxy headers the app should send with each network request",
|
||||||
|
"headers_settings_tile_title": "Custom proxy headers",
|
||||||
"home_page_add_to_album_conflicts": "Added {added} assets to album {album}. {failed} assets are already in the album.",
|
"home_page_add_to_album_conflicts": "Added {added} assets to album {album}. {failed} assets are already in the album.",
|
||||||
"home_page_add_to_album_err_local": "Can not add local assets to albums yet, skipping",
|
"home_page_add_to_album_err_local": "Can not add local assets to albums yet, skipping",
|
||||||
"home_page_add_to_album_success": "Added {added} assets to album {album}.",
|
"home_page_add_to_album_success": "Added {added} assets to album {album}.",
|
||||||
@@ -295,6 +304,8 @@
|
|||||||
"memories_check_back_tomorrow": "Check back tomorrow for more memories",
|
"memories_check_back_tomorrow": "Check back tomorrow for more memories",
|
||||||
"memories_start_over": "Start Over",
|
"memories_start_over": "Start Over",
|
||||||
"memories_swipe_to_close": "Swipe up to close",
|
"memories_swipe_to_close": "Swipe up to close",
|
||||||
|
"memories_year_ago": "A year ago",
|
||||||
|
"memories_years_ago": "{} years ago",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "Motion Photos",
|
"motion_photos_page_title": "Motion Photos",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
"multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping",
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
"advanced_settings_log_level_title": "Loggnivå: {}",
|
"advanced_settings_log_level_title": "Loggnivå: {}",
|
||||||
"advanced_settings_prefer_remote_subtitle": "Noen enheter er veldige trege til å hente mikrobilder fra enheten. Aktiver denne innstillingen for å hente de eksternt istedenfor.",
|
"advanced_settings_prefer_remote_subtitle": "Noen enheter er veldige trege til å hente mikrobilder fra enheten. Aktiver denne innstillingen for å hente de eksternt istedenfor.",
|
||||||
"advanced_settings_prefer_remote_title": "Foretrekk eksterne bilder",
|
"advanced_settings_prefer_remote_title": "Foretrekk eksterne bilder",
|
||||||
|
"advanced_settings_proxy_headers_subtitle": "Define proxy headers Immich should send with each network request",
|
||||||
|
"advanced_settings_proxy_headers_title": "Proxy Headers",
|
||||||
"advanced_settings_self_signed_ssl_subtitle": "Hopper over SSL sertifikatverifikasjon for server-endepunkt. Påkrevet for selvsignerte sertifikater.",
|
"advanced_settings_self_signed_ssl_subtitle": "Hopper over SSL sertifikatverifikasjon for server-endepunkt. Påkrevet for selvsignerte sertifikater.",
|
||||||
"advanced_settings_self_signed_ssl_title": "Tillat selvsignerte SSL sertifikater",
|
"advanced_settings_self_signed_ssl_title": "Tillat selvsignerte SSL sertifikater",
|
||||||
"advanced_settings_tile_subtitle": "Avanserte brukerinnstillinger",
|
"advanced_settings_tile_subtitle": "Avanserte brukerinnstillinger",
|
||||||
@@ -203,6 +205,13 @@
|
|||||||
"favorites_page_title": "Favoritter",
|
"favorites_page_title": "Favoritter",
|
||||||
"haptic_feedback_switch": "Aktivert haptisk tilbakemelding",
|
"haptic_feedback_switch": "Aktivert haptisk tilbakemelding",
|
||||||
"haptic_feedback_title": "Haptisk tilbakemelding",
|
"haptic_feedback_title": "Haptisk tilbakemelding",
|
||||||
|
"header_settings_add_header_tip": "Add Header",
|
||||||
|
"header_settings_field_validator_msg": "Value cannot be empty",
|
||||||
|
"header_settings_header_name_input": "Header name",
|
||||||
|
"header_settings_header_value_input": "Header value",
|
||||||
|
"header_settings_page_title": "Proxy Headers",
|
||||||
|
"headers_settings_tile_subtitle": "Define proxy headers the app should send with each network request",
|
||||||
|
"headers_settings_tile_title": "Custom proxy headers",
|
||||||
"home_page_add_to_album_conflicts": "Lagt til {added} objekter til album {album}. {failed} objekter er allerede i albumet.",
|
"home_page_add_to_album_conflicts": "Lagt til {added} objekter til album {album}. {failed} objekter er allerede i albumet.",
|
||||||
"home_page_add_to_album_err_local": "Kan ikke legge til lokale objekter til album enda, hopper over",
|
"home_page_add_to_album_err_local": "Kan ikke legge til lokale objekter til album enda, hopper over",
|
||||||
"home_page_add_to_album_success": "Lagt til {added} objekter til album {album}.",
|
"home_page_add_to_album_success": "Lagt til {added} objekter til album {album}.",
|
||||||
@@ -295,6 +304,8 @@
|
|||||||
"memories_check_back_tomorrow": "Sjekk igjen i morgen for flere minner",
|
"memories_check_back_tomorrow": "Sjekk igjen i morgen for flere minner",
|
||||||
"memories_start_over": "Start på nytt",
|
"memories_start_over": "Start på nytt",
|
||||||
"memories_swipe_to_close": "Swipe opp for å lukke",
|
"memories_swipe_to_close": "Swipe opp for å lukke",
|
||||||
|
"memories_year_ago": "Ett år siden",
|
||||||
|
"memories_years_ago": "{} år siden",
|
||||||
"monthly_title_text_date_format": "MMMM y",
|
"monthly_title_text_date_format": "MMMM y",
|
||||||
"motion_photos_page_title": "Bevegelige bilder",
|
"motion_photos_page_title": "Bevegelige bilder",
|
||||||
"multiselect_grid_edit_date_time_err_read_only": "Kan ikke endre dato på objekt(er) med kun lese-rettigheter, hopper over",
|
"multiselect_grid_edit_date_time_err_read_only": "Kan ikke endre dato på objekt(er) med kun lese-rettigheter, hopper over",
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user