Compare commits
352 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3d251f51fc | ||
|
|
57704522cd | ||
|
|
787926c111 | ||
|
|
08b424b3df | ||
|
|
736a946101 | ||
|
|
6f6f847ee2 | ||
|
|
13be271df7 | ||
|
|
b423852fad | ||
|
|
fe3d6b870a | ||
|
|
14be63039f | ||
|
|
d339d4c8dd | ||
|
|
b0d5cb62fa | ||
|
|
975d23ee5c | ||
|
|
8a421831ab | ||
|
|
c8d3faec6d | ||
|
|
8a45c258c5 | ||
|
|
d45ff72c9c | ||
|
|
137d246d6a | ||
|
|
e80d37bf8f | ||
|
|
b970a40b4e | ||
|
|
1e32a5fffd | ||
|
|
2e5cd986dd | ||
|
|
635eee9e5e | ||
|
|
ae3ea9e531 | ||
|
|
5b241f0b64 | ||
|
|
1a64075027 | ||
|
|
100866be37 | ||
|
|
2179530084 | ||
|
|
d500ef77cf | ||
|
|
4952b3a2d6 | ||
|
|
a9859bc029 | ||
|
|
561b208508 | ||
|
|
de59d02ad7 | ||
|
|
017a34fc10 | ||
|
|
d314805caf | ||
|
|
eb9481b668 | ||
|
|
1564807aa0 | ||
|
|
dd8d113334 | ||
|
|
258bc328e0 | ||
|
|
c0de3aa35c | ||
|
|
a1a62b00a0 | ||
|
|
db628cec11 | ||
|
|
6f7071b12d | ||
|
|
e9c171f7ab | ||
|
|
983abf5e14 | ||
|
|
91e27affeb | ||
|
|
d76b3c8f78 | ||
|
|
fb42a736f1 | ||
|
|
a68fbcc520 | ||
|
|
9fc70fc24e | ||
|
|
1f17720be2 | ||
|
|
ab5b92ae68 | ||
|
|
767410959a | ||
|
|
e3b043e0e1 | ||
|
|
0979906933 | ||
|
|
e241fd0418 | ||
|
|
8e3a7caebd | ||
|
|
b03ce897c7 | ||
|
|
d7c1005a50 | ||
|
|
1111c15f77 | ||
|
|
fc12a9f751 | ||
|
|
cfcae39699 | ||
|
|
4c923bae7d | ||
|
|
a5a6bebf0b | ||
|
|
6f1d0a3caa | ||
|
|
2b5484539d | ||
|
|
5d21dc95ea | ||
|
|
e32b6c98df | ||
|
|
7b9248c10a | ||
|
|
4853240de9 | ||
|
|
d5f2e3e45c | ||
|
|
ad680b6a35 | ||
|
|
4cb74f0fe4 | ||
|
|
333ab1124b | ||
|
|
48393c215b | ||
|
|
ec6a7ae97c | ||
|
|
808d6423be | ||
|
|
9076f3e69e | ||
|
|
7e526f87b4 | ||
|
|
fc585bffcc | ||
|
|
d6f2ca6aaa | ||
|
|
2dcccb37a0 | ||
|
|
c584791b65 | ||
|
|
ed551500e7 | ||
|
|
94b2ea9b5f | ||
|
|
8b001b87d2 | ||
|
|
b06ddec2d5 | ||
|
|
d04f340b5b | ||
|
|
aaaf1a6cf8 | ||
|
|
23e4449f27 | ||
|
|
51785a1ead | ||
|
|
49f66be8af | ||
|
|
009b6e3ca5 | ||
|
|
c011b06bea | ||
|
|
34d300d1da | ||
|
|
468e620372 | ||
|
|
e05153d7bb | ||
|
|
4aa4a3b597 | ||
|
|
b1d17302bc | ||
|
|
cc3ffcbb84 | ||
|
|
eda9e580c9 | ||
|
|
76a07a3ebc | ||
|
|
abe87686a2 | ||
|
|
6371c11fc5 | ||
|
|
d5596cf6a2 | ||
|
|
2f64af9cb2 | ||
|
|
b0d5c7035b | ||
|
|
0c61521521 | ||
|
|
3497a0de54 | ||
|
|
117f2fa00d | ||
|
|
2c67090e3c | ||
|
|
10ccbeab35 | ||
|
|
b49f66bbc9 | ||
|
|
9adbbd42be | ||
|
|
8563bd463c | ||
|
|
da5a6d2272 | ||
|
|
0854737be2 | ||
|
|
6f3f8b0a48 | ||
|
|
f0e272d0f2 | ||
|
|
5e207aa7c1 | ||
|
|
e0b80f49b6 | ||
|
|
97bbe42599 | ||
|
|
089dbdbd7e | ||
|
|
833c099025 | ||
|
|
4e526dfaae | ||
|
|
cae37657e9 | ||
|
|
1a94530935 | ||
|
|
75d28d3c58 | ||
|
|
cd59f7aad6 | ||
|
|
2f9fcd96c7 | ||
|
|
c74fba483d | ||
|
|
193dd01e06 | ||
|
|
2400004f41 | ||
|
|
b862c20e8e | ||
|
|
c0ed623d26 | ||
|
|
501b96baf7 | ||
|
|
d2600e0ddd | ||
|
|
7d799b785e | ||
|
|
e36b620020 | ||
|
|
1efc74dabc | ||
|
|
54f98053a8 | ||
|
|
6745826f35 | ||
|
|
bbd897b8ff | ||
|
|
586590e9ec | ||
|
|
4bf50a0b46 | ||
|
|
40832f0ea7 | ||
|
|
32a065afc7 | ||
|
|
4dafc74223 | ||
|
|
8adf1231a3 | ||
|
|
c00624f209 | ||
|
|
eccde8fa07 | ||
|
|
0616a66b05 | ||
|
|
67453d18ff | ||
|
|
792a87e407 | ||
|
|
6da50626e1 | ||
|
|
6239b3b309 | ||
|
|
b9bc621e2a | ||
|
|
e10bbfa933 | ||
|
|
2dd301e292 | ||
|
|
75edc6de0f | ||
|
|
780c5183e3 | ||
|
|
25a10784eb | ||
|
|
6e1d09fc32 | ||
|
|
73a2063d96 | ||
|
|
deb1e7f41f | ||
|
|
f45f719b9d | ||
|
|
325639b308 | ||
|
|
386eef046d | ||
|
|
db6b14361d | ||
|
|
719f074ccf | ||
|
|
646b912da8 | ||
|
|
b29c43d86a | ||
|
|
7ce64ecf05 | ||
|
|
9a332074c7 | ||
|
|
dd02f1025f | ||
|
|
d7bfab7b13 | ||
|
|
05cf5d57a9 | ||
|
|
f56eaae019 | ||
|
|
0d436db3ea | ||
|
|
6c8b29f326 | ||
|
|
23e76b0bd9 | ||
|
|
82e8cd0f8d | ||
|
|
87d84b922f | ||
|
|
04955a4123 | ||
|
|
54831878e0 | ||
|
|
08ed71e51e | ||
|
|
3a1d5de742 | ||
|
|
e15be5bf9a | ||
|
|
01afeefeb9 | ||
|
|
532bd6fe12 | ||
|
|
416e30ede2 | ||
|
|
ceb81d00fc | ||
|
|
8adca31c24 | ||
|
|
3cce43309c | ||
|
|
63ad802013 | ||
|
|
9313e70575 | ||
|
|
838ea56605 | ||
|
|
9ac087c59c | ||
|
|
f52e076cb3 | ||
|
|
8857d0b8df | ||
|
|
950989a85e | ||
|
|
a4c215751e | ||
|
|
2ca560ebf8 | ||
|
|
1f631eafce | ||
|
|
6f605d4a35 | ||
|
|
1918625be9 | ||
|
|
bdf35b6688 | ||
|
|
2ac54ce4bd | ||
|
|
96d75c9ad4 | ||
|
|
dac4020f27 | ||
|
|
a5f49b065c | ||
|
|
d5d0624311 | ||
|
|
8708867c1c | ||
|
|
8f11529a75 | ||
|
|
0aaeab124d | ||
|
|
1cc184ed10 | ||
|
|
830f4268c3 | ||
|
|
977740045a | ||
|
|
2a1dcbc28b | ||
|
|
21f8ab647f | ||
|
|
aef5a48fc6 | ||
|
|
434c1a0f20 | ||
|
|
5fd2496774 | ||
|
|
7411bcbb30 | ||
|
|
7d6d51f4a5 | ||
|
|
5777693fad | ||
|
|
b53cc4f9db | ||
|
|
9d57039274 | ||
|
|
12217bde8a | ||
|
|
37f802d1fe | ||
|
|
df1710f4cc | ||
|
|
0fec34d316 | ||
|
|
a0b8312ce4 | ||
|
|
8abe6909ca | ||
|
|
25cff6a748 | ||
|
|
243c98a02e | ||
|
|
c9a6820de7 | ||
|
|
7d586492f3 | ||
|
|
807bdfeda9 | ||
|
|
1f25df308a | ||
|
|
2efa8b6960 | ||
|
|
7c9d2018d8 | ||
|
|
ab90b01122 | ||
|
|
d04ef319b8 | ||
|
|
368142e79b | ||
|
|
7d45ae68a6 | ||
|
|
98bedcf1e5 | ||
|
|
3377fa4640 | ||
|
|
641c05c6fe | ||
|
|
e157a69d86 | ||
|
|
3d468c369c | ||
|
|
6c7679714b | ||
|
|
71d8567f18 | ||
|
|
cc6253ba38 | ||
|
|
3ea107be5a | ||
|
|
4ed96cf1bd | ||
|
|
9323cc76d9 | ||
|
|
da9b9c8c69 | ||
|
|
3c5c0ea68f | ||
|
|
2b988e1d5d | ||
|
|
8bcb2558b6 | ||
|
|
b8785a5b93 | ||
|
|
b00631d186 | ||
|
|
de5a6b2c35 | ||
|
|
3beb8193ae | ||
|
|
a2549c5bbd | ||
|
|
98a8be82e2 | ||
|
|
5c86e13239 | ||
|
|
10cb612fb1 | ||
|
|
a9a769d902 | ||
|
|
846e35f57e | ||
|
|
a3b9a0be3a | ||
|
|
2a3235f606 | ||
|
|
08b221c270 | ||
|
|
3102c3128f | ||
|
|
9ebed3c1b4 | ||
|
|
24d672a0ff | ||
|
|
e9f99302c1 | ||
|
|
5cdf7671ed | ||
|
|
4dab50c10a | ||
|
|
c416dd30e2 | ||
|
|
4ebc8870c2 | ||
|
|
bf3f4e560d | ||
|
|
4be55428d2 | ||
|
|
e9c9b7a3e2 | ||
|
|
2d2cfb0349 | ||
|
|
98998cccbc | ||
|
|
03d484aba2 | ||
|
|
88a2966666 | ||
|
|
e408e8ca4a | ||
|
|
9bfb4dfd06 | ||
|
|
7dc7281e69 | ||
|
|
87fea29e32 | ||
|
|
2cf42e867c | ||
|
|
83a2669ff5 | ||
|
|
824409351e | ||
|
|
d1ea6a897e | ||
|
|
5d3e8f17d1 | ||
|
|
78a5fe2d37 | ||
|
|
5ad4e5b614 | ||
|
|
000d0a08f4 | ||
|
|
917f1dea9f | ||
|
|
e309647f1b | ||
|
|
57136e48fb | ||
|
|
8c315dfeb1 | ||
|
|
6e9749d6c4 | ||
|
|
bf6f94f69f | ||
|
|
575154fdea | ||
|
|
857bbe3c3b | ||
|
|
0a0b255505 | ||
|
|
73b4b032b1 | ||
|
|
8234e44921 | ||
|
|
36197cca98 | ||
|
|
7a25d359b7 | ||
|
|
7cfb257c00 | ||
|
|
b660240059 | ||
|
|
125ec1e85f | ||
|
|
d31b35873f | ||
|
|
e1c520b9e7 | ||
|
|
1361f18964 | ||
|
|
0f00f22212 | ||
|
|
0d543bbb0a | ||
|
|
86b3bdb90b | ||
|
|
d47cdfb647 | ||
|
|
ac5c17e8be | ||
|
|
db67093391 | ||
|
|
318fba6c97 | ||
|
|
2d63fa80b4 | ||
|
|
1dc211a046 | ||
|
|
f71f379529 | ||
|
|
bee95b4977 | ||
|
|
9f8aaa57b6 | ||
|
|
2c1aab154a | ||
|
|
37cfac27b8 | ||
|
|
11b2e2a6e2 | ||
|
|
d555ee737b | ||
|
|
12a6a7d95a | ||
|
|
caac3bfc95 | ||
|
|
05630776a0 | ||
|
|
72c947cbaf | ||
|
|
53fb3a36f7 | ||
|
|
6b3892987a | ||
|
|
390919c439 | ||
|
|
09ab06ae6c | ||
|
|
ad9373312b | ||
|
|
bd71e087d4 | ||
|
|
c90dcde7cc | ||
|
|
d91cc3616b | ||
|
|
74cd3d66c6 | ||
|
|
e6f9d9a31a | ||
|
|
b71a86142b | ||
|
|
6e4ba6184b |
2
.github/PULL_REQUEST_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
blank_issues_enabled: false
|
||||
blank_pull_request_template_enabled: false
|
||||
22
.github/PULL_REQUEST_TEMPLATE/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
## Description
|
||||
<!--- Describe your changes in detail -->
|
||||
<!--- Why is this change required? What problem does it solve? -->
|
||||
<!--- If it fixes an open issue, please link to the issue here. -->
|
||||
|
||||
Fixes # (issue)
|
||||
|
||||
|
||||
## How Has This Been Tested?
|
||||
|
||||
<!-- Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration -->
|
||||
|
||||
- [ ] Test A
|
||||
- [ ] Test B
|
||||
|
||||
## Screenshots (if appropriate):
|
||||
|
||||
|
||||
## Checklist:
|
||||
|
||||
- [ ] I have performed a self-review of my own code
|
||||
- [ ] I have made corresponding changes to the documentation if applicable
|
||||
10
.github/workflows/build-mobile.yml
vendored
@@ -11,9 +11,15 @@ on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-sign-android:
|
||||
name: Build and sign Android
|
||||
# Skip when PR from a fork
|
||||
if: ${{ !github.event.pull_request.head.repo.fork }}
|
||||
runs-on: macos-12
|
||||
|
||||
steps:
|
||||
@@ -24,7 +30,7 @@ jobs:
|
||||
github_ref="${{ github.sha }}"
|
||||
ref="${input_ref:-$github_ref}"
|
||||
echo "ref=$ref" >> $GITHUB_OUTPUT
|
||||
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ steps.get-ref.outputs.ref }}
|
||||
@@ -39,7 +45,7 @@ jobs:
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: "3.3.10"
|
||||
flutter-version: "3.7.3"
|
||||
cache: true
|
||||
|
||||
- name: Create the Keystore
|
||||
|
||||
10
.github/workflows/cache-cleanup.yml
vendored
@@ -4,24 +4,28 @@ on:
|
||||
types:
|
||||
- closed
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
cleanup:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
|
||||
- name: Cleanup
|
||||
run: |
|
||||
gh extension install actions/gh-actions-cache
|
||||
|
||||
|
||||
REPO=${{ github.repository }}
|
||||
BRANCH=${{ github.ref }}
|
||||
|
||||
echo "Fetching list of cache keys"
|
||||
cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH -L 100 | cut -f 1 )
|
||||
|
||||
## Setting this to not fail the workflow while deleting cache keys.
|
||||
## Setting this to not fail the workflow while deleting cache keys.
|
||||
set +e
|
||||
echo "Deleting caches..."
|
||||
for cacheKey in $cacheKeysForPR
|
||||
|
||||
10
.github/workflows/codeql-analysis.yml
vendored
@@ -20,6 +20,10 @@ on:
|
||||
schedule:
|
||||
- cron: '20 13 * * 1'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
@@ -48,11 +52,11 @@ jobs:
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
|
||||
|
||||
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||
# queries: security-extended,security-and-quality
|
||||
|
||||
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
@@ -61,7 +65,7 @@ jobs:
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
|
||||
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
||||
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
||||
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
||||
|
||||
# - run: |
|
||||
|
||||
4
.github/workflows/dispatch_sdk_update.yml
vendored
@@ -5,6 +5,10 @@ on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
update-sdk-repos:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
19
.github/workflows/docker.yml
vendored
@@ -9,6 +9,13 @@ on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
build_and_push:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -19,13 +26,17 @@ jobs:
|
||||
include:
|
||||
- context: "server"
|
||||
image: "immich-server"
|
||||
platforms: "linux/arm/v7,linux/amd64,linux/arm64"
|
||||
- context: "web"
|
||||
image: "immich-web"
|
||||
platforms: "linux/arm/v7,linux/amd64,linux/arm64"
|
||||
- context: "machine-learning"
|
||||
image: "immich-machine-learning"
|
||||
platforms: "linux/amd64,linux/arm64"
|
||||
- context: "nginx"
|
||||
image: "immich-proxy"
|
||||
|
||||
platforms: "linux/arm/v7,linux/amd64,linux/arm64"
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
@@ -34,7 +45,7 @@ jobs:
|
||||
uses: docker/setup-qemu-action@v2.1.0
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2.4.1
|
||||
uses: docker/setup-buildx-action@v2.5.0
|
||||
# Workaround to fix error:
|
||||
# failed to push: failed to copy: io: read/write on closed pipe
|
||||
# See https://github.com/docker/build-push-action/issues/761
|
||||
@@ -49,7 +60,7 @@ jobs:
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2
|
||||
# Skip when PR from a fork
|
||||
@@ -92,7 +103,7 @@ jobs:
|
||||
uses: docker/build-push-action@v4.0.0
|
||||
with:
|
||||
context: ${{ matrix.context }}
|
||||
platforms: linux/arm/v7,linux/amd64,linux/arm64
|
||||
platforms: ${{ matrix.platforms }}
|
||||
# Skip pushing when PR from a fork
|
||||
push: ${{ !github.event.pull_request.head.repo.fork }}
|
||||
cache-from: type=registry,ref=ghcr.io/${{ github.repository_owner }}/immich-build-cache:${{matrix.image}}
|
||||
|
||||
19
.github/workflows/github-repo-stats.yml
vendored
@@ -1,19 +0,0 @@
|
||||
name: github-repo-stats
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# Run this once per day, towards the end of the day for keeping the most
|
||||
# recent data point most meaningful (hours are interpreted in UTC).
|
||||
- cron: "0 23 * * *"
|
||||
workflow_dispatch: # Allow for running this manually.
|
||||
|
||||
jobs:
|
||||
j1:
|
||||
name: github-repo-stats
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: run-ghrs
|
||||
# Use latest release.
|
||||
uses: jgehrcke/github-repo-stats@RELEASE
|
||||
with:
|
||||
ghtoken: ${{ secrets.GHRS_GITHUB_API_TOKEN }}
|
||||
17
.github/workflows/prepare-release.yml
vendored
@@ -17,13 +17,17 @@ on:
|
||||
required: false
|
||||
type: boolean
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-root
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
bump_version:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
|
||||
outputs:
|
||||
ref: ${{ steps.push-tag.outputs.commit_long_sha }}
|
||||
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
@@ -37,12 +41,13 @@ jobs:
|
||||
id: push-tag
|
||||
uses: EndBug/add-and-commit@v9
|
||||
with:
|
||||
author_name: Immich Release Bot
|
||||
author_email: bot@immich.app
|
||||
author_name: Alex The Bot
|
||||
author_email: alex.tran1502@gmail.com
|
||||
default_author: user_info
|
||||
message: "Version ${{ env.IMMICH_VERSION }}"
|
||||
tag: ${{ env.IMMICH_VERSION }}
|
||||
push: true
|
||||
|
||||
|
||||
build_mobile:
|
||||
uses: ./.github/workflows/build-mobile.yml
|
||||
needs: bump_version
|
||||
@@ -59,7 +64,7 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
token: ${{ secrets.ORG_RELEASE_TOKEN }}
|
||||
|
||||
|
||||
- name: Download APK
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
|
||||
6
.github/workflows/static_analysis.yml
vendored
@@ -5,6 +5,10 @@ on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
mobile-dart-analyze:
|
||||
name: Run Dart Code Analysis
|
||||
@@ -19,7 +23,7 @@ jobs:
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: 'stable'
|
||||
flutter-version: '3.3.10'
|
||||
flutter-version: '3.7.3'
|
||||
|
||||
- name: Install dependencies
|
||||
run: dart pub get
|
||||
|
||||
225
.github/workflows/test.yml
vendored
@@ -5,10 +5,13 @@ on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
e2e-tests:
|
||||
name: Run end-to-end test suites
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
@@ -21,24 +24,62 @@ jobs:
|
||||
server-unit-tests:
|
||||
name: Run server unit test suites and checks
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./server
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Run tests
|
||||
run: cd server && npm ci && npm run check:all
|
||||
- name: Run npm install
|
||||
run: npm ci
|
||||
|
||||
- name: Run linter
|
||||
run: npm run lint
|
||||
if: ${{ !cancelled() }}
|
||||
|
||||
- name: Run formatter
|
||||
run: npm run format
|
||||
if: ${{ !cancelled() }}
|
||||
|
||||
- name: Run tsc
|
||||
run: npm run check
|
||||
if: ${{ !cancelled() }}
|
||||
|
||||
- name: Run unit tests & coverage
|
||||
run: npm run test:cov
|
||||
if: ${{ !cancelled() }}
|
||||
|
||||
web-unit-tests:
|
||||
name: Run web unit test suites and checks
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./web
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Run tests
|
||||
run: cd web && npm ci && npm run check:all
|
||||
- name: Run npm install
|
||||
run: npm ci
|
||||
|
||||
- name: Run linter
|
||||
run: npm run lint
|
||||
if: ${{ !cancelled() }}
|
||||
|
||||
- name: Run formatter
|
||||
run: npm run format
|
||||
if: ${{ !cancelled() }}
|
||||
|
||||
- name: Run svelte checks
|
||||
run: npm run check
|
||||
if: ${{ !cancelled() }}
|
||||
|
||||
- name: Run unit tests & coverage
|
||||
run: npm run test:cov
|
||||
if: ${{ !cancelled() }}
|
||||
|
||||
mobile-unit-tests:
|
||||
name: Run mobile unit tests
|
||||
@@ -48,47 +89,149 @@ jobs:
|
||||
- name: Setup Flutter SDK
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: 'stable'
|
||||
flutter-version: '3.3.10'
|
||||
channel: "stable"
|
||||
flutter-version: "3.7.3"
|
||||
- name: Run tests
|
||||
working-directory: ./mobile
|
||||
run: flutter test
|
||||
|
||||
mobile-integration-tests:
|
||||
name: Run mobile end-to-end integration tests
|
||||
runs-on: macos-latest
|
||||
generated-api-up-to-date:
|
||||
name: Check generated files are up-to-date
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-java@v3
|
||||
- name: Run API generation
|
||||
run: cd server && npm ci && npm run api:generate
|
||||
- name: Find file changes
|
||||
uses: tj-actions/verify-changed-files@v13.1
|
||||
id: verify-changed-files
|
||||
with:
|
||||
distribution: 'adopt'
|
||||
java-version: '11'
|
||||
- name: Cache android SDK
|
||||
uses: actions/cache@v3
|
||||
id: android-sdk
|
||||
files: |
|
||||
mobile/openapi
|
||||
web/src/api/open-api
|
||||
- name: Verify files have not changed
|
||||
if: steps.verify-changed-files.outputs.files_changed == 'true'
|
||||
run: |
|
||||
echo "ERROR: Generated files not up to date!"
|
||||
echo "Changed files: ${{ steps.verify-changed-files.outputs.changed_files }}"
|
||||
exit 1
|
||||
|
||||
generated-typeorm-migrations-up-to-date:
|
||||
name: Check generated TypeORM migrations are up-to-date
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
postgres:
|
||||
image: postgres
|
||||
env:
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_DB: immich
|
||||
options: >-
|
||||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
ports:
|
||||
- 5432:5432
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install server dependencies
|
||||
run: |
|
||||
cd server
|
||||
npm ci
|
||||
- name: Run existing migrations
|
||||
run: |
|
||||
cd server
|
||||
npm run typeorm:migrations:run
|
||||
- name: Generate new migrations
|
||||
continue-on-error: true
|
||||
run: |
|
||||
cd server
|
||||
npm run typeorm:migrations:generate ./libs/infra/src/migrations/TestMigration
|
||||
- name: Find file changes
|
||||
uses: tj-actions/verify-changed-files@v13.1
|
||||
id: verify-changed-files
|
||||
with:
|
||||
key: android-sdk
|
||||
path: |
|
||||
/usr/local/lib/android/
|
||||
~/.android
|
||||
- name: Setup Android SDK
|
||||
if: steps.android-sdk.outputs.cache-hit != 'true'
|
||||
uses: android-actions/setup-android@v2
|
||||
- name: Setup Flutter SDK
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: 'stable'
|
||||
flutter-version: '3.3.10'
|
||||
- name: Run integration tests
|
||||
uses: reactivecircus/android-emulator-runner@v2.27.0
|
||||
with:
|
||||
working-directory: ./mobile
|
||||
api-level: 29
|
||||
arch: x86_64
|
||||
profile: pixel
|
||||
target: default
|
||||
emulator-options: -no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim
|
||||
disable-linux-hw-accel: false
|
||||
script: |
|
||||
flutter pub get
|
||||
flutter test integration_test
|
||||
files: |
|
||||
server/libs/infra/src/migrations/
|
||||
- name: Verify files have not changed
|
||||
if: steps.verify-changed-files.outputs.files_changed == 'true'
|
||||
run: |
|
||||
echo "ERROR: Generated files not up to date!"
|
||||
echo "Changed files: ${{ steps.verify-changed-files.outputs.changed_files }}"
|
||||
exit 1
|
||||
|
||||
# mobile-integration-tests:
|
||||
# name: Run mobile end-to-end integration tests
|
||||
# runs-on: macos-latest
|
||||
# steps:
|
||||
# - uses: actions/checkout@v3
|
||||
# - uses: actions/setup-java@v3
|
||||
# with:
|
||||
# distribution: 'zulu'
|
||||
# java-version: '12.x'
|
||||
# cache: 'gradle'
|
||||
# - name: Cache android SDK
|
||||
# uses: actions/cache@v3
|
||||
# id: android-sdk
|
||||
# with:
|
||||
# key: android-sdk
|
||||
# path: |
|
||||
# /usr/local/lib/android/
|
||||
# ~/.android
|
||||
# - name: Cache Gradle
|
||||
# uses: actions/cache@v3
|
||||
# with:
|
||||
# path: |
|
||||
# ./mobile/build/
|
||||
# ./mobile/android/.gradle/
|
||||
# key: ${{ runner.os }}-flutter-${{ hashFiles('**/*.gradle*', 'pubspec.lock') }}
|
||||
# - name: Setup Android SDK
|
||||
# if: steps.android-sdk.outputs.cache-hit != 'true'
|
||||
# uses: android-actions/setup-android@v2
|
||||
# - name: AVD cache
|
||||
# uses: actions/cache@v3
|
||||
# id: avd-cache
|
||||
# with:
|
||||
# path: |
|
||||
# ~/.android/avd/*
|
||||
# ~/.android/adb*
|
||||
# key: avd-29
|
||||
# - name: create AVD and generate snapshot for caching
|
||||
# if: steps.avd-cache.outputs.cache-hit != 'true'
|
||||
# uses: reactivecircus/android-emulator-runner@v2.27.0
|
||||
# with:
|
||||
# working-directory: ./mobile
|
||||
# cores: 2
|
||||
# api-level: 29
|
||||
# arch: x86_64
|
||||
# profile: pixel
|
||||
# target: default
|
||||
# force-avd-creation: false
|
||||
# emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
|
||||
# disable-animations: false
|
||||
# script: echo "Generated AVD snapshot for caching."
|
||||
# - name: Setup Flutter SDK
|
||||
# uses: subosito/flutter-action@v2
|
||||
# with:
|
||||
# channel: 'stable'
|
||||
# flutter-version: '3.7.3'
|
||||
# cache: true
|
||||
# - name: Run integration tests
|
||||
# uses: Wandalen/wretry.action@master
|
||||
# with:
|
||||
# action: reactivecircus/android-emulator-runner@v2.27.0
|
||||
# with: |
|
||||
# working-directory: ./mobile
|
||||
# cores: 2
|
||||
# api-level: 29
|
||||
# arch: x86_64
|
||||
# profile: pixel
|
||||
# target: default
|
||||
# force-avd-creation: false
|
||||
# emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
|
||||
# disable-animations: true
|
||||
# script: |
|
||||
# flutter pub get
|
||||
# flutter test integration_test
|
||||
# attempt_limit: 3
|
||||
|
||||
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "mobile/.isar"]
|
||||
path = mobile/.isar
|
||||
url = https://github.com/isar/isar
|
||||
@@ -1,17 +0,0 @@
|
||||
# Deployment checklist for iOS/Android/Server
|
||||
|
||||
[ ] Up version in [mobile/pubspec.yml](/mobile/pubspec.yaml)
|
||||
|
||||
[ ] Up version in [docker/docker-compose.yml](/docker/docker-compose.yml) for `immich_server` service
|
||||
|
||||
[ ] Up version in [docker/docker-compose.gpu.yml](/docker/docker-compose.gpu.yml) for `immich_server` service
|
||||
|
||||
[ ] Up version in [docker/docker-compose.dev.yml](/docker/docker-compose.dev.yml) for `immich_server` service
|
||||
|
||||
[ ] Up version in [server/src/constants/server_version.constant.ts](/server/src/constants/server_version.constant.ts)
|
||||
|
||||
[ ] Up version in iOS Fastlane [/mobile/ios/fastlane/Fastfile](/mobile/ios/fastlane/Fastfile)
|
||||
|
||||
[ ] Add changelog to [Android Fastlane F-droid folder](/mobile/android/fastlane/metadata/android/en-US/changelogs)
|
||||
|
||||
All of the version should be the same.
|
||||
40
README.md
@@ -61,25 +61,25 @@ Spec: Free-tier Oracle VM - Amsterdam - 2.4Ghz quad-core ARM64 CPU, 24GB RAM
|
||||
|
||||
# Features
|
||||
|
||||
| Features | Mobile | Web |
|
||||
| ------------------------------------------- | ------- | --- |
|
||||
| Upload and view videos and photos | Yes | Yes |
|
||||
| Auto backup when the app is opened | Yes | N/A |
|
||||
| Selective album(s) for backup | Yes | N/A |
|
||||
| Download photos and videos to local device | Yes | Yes |
|
||||
| Multi-user support | Yes | Yes |
|
||||
| Album and Shared albums | Yes | Yes |
|
||||
| Scrubbable/draggable scrollbar | Yes | Yes |
|
||||
| Support RAW (HEIC, HEIF, DNG, Apple ProRaw) | Yes | Yes |
|
||||
| Metadata view (EXIF, map) | Yes | Yes |
|
||||
| Search by metadata, objects and image tags | Yes | No |
|
||||
| Administrative functions (user management) | N/A | Yes |
|
||||
| Background backup | Android | N/A |
|
||||
| Virtual scroll | Yes | Yes |
|
||||
| OAuth support | Yes | Yes |
|
||||
| LivePhoto backup and playback | iOS | Yes |
|
||||
| User-defined storage structure | Yes | Yes |
|
||||
| Public Sharing | N/A | Yes |
|
||||
| Features | Mobile | Web |
|
||||
| ------------------------------------------- | ------ | --- |
|
||||
| Upload and view videos and photos | Yes | Yes |
|
||||
| Auto backup when the app is opened | Yes | N/A |
|
||||
| Selective album(s) for backup | Yes | N/A |
|
||||
| Download photos and videos to local device | Yes | Yes |
|
||||
| Multi-user support | Yes | Yes |
|
||||
| Album and Shared albums | Yes | Yes |
|
||||
| Scrubbable/draggable scrollbar | Yes | Yes |
|
||||
| Support RAW (HEIC, HEIF, DNG, Apple ProRaw) | Yes | Yes |
|
||||
| Metadata view (EXIF, map) | Yes | Yes |
|
||||
| Search by metadata, objects and CLIP | Yes | No |
|
||||
| Administrative functions (user management) | N/A | Yes |
|
||||
| Background backup | Yes | N/A |
|
||||
| Virtual scroll | Yes | Yes |
|
||||
| OAuth support | Yes | Yes |
|
||||
| LivePhoto backup and playback | iOS | Yes |
|
||||
| User-defined storage structure | Yes | Yes |
|
||||
| Public Sharing | N/A | Yes |
|
||||
|
||||
# Support the project
|
||||
|
||||
@@ -92,7 +92,7 @@ If you feel like this is the right cause and the app is something you are seeing
|
||||
## Donation
|
||||
|
||||
- [Monthly donation](https://github.com/sponsors/alextran1502) via GitHub Sponsors
|
||||
- [One-time donation](https://github.com/sponsors/alextran1502?frequency=one-time&sponsor=alextran1502) via Github Sponsors
|
||||
- [One-time donation](https://github.com/sponsors/alextran1502?frequency=one-time&sponsor=alextran1502) via GitHub Sponsors
|
||||
- [Librepay](https://liberapay.com/alex.tran1502/)
|
||||
- [buymeacoffee](https://www.buymeacoffee.com/altran1502)
|
||||
- Bitcoin: 1FvEp6P6NM8EZEkpGUFAN2LqJ1gxusNxZX
|
||||
|
||||
@@ -17,3 +17,5 @@ ENABLE_MAPBOX=false
|
||||
# WEB
|
||||
MAPBOX_KEY=
|
||||
VITE_SERVER_ENDPOINT=http://localhost:2283/api
|
||||
|
||||
TYPESENSE_ENABLED=false
|
||||
|
||||
@@ -23,6 +23,7 @@ services:
|
||||
depends_on:
|
||||
- redis
|
||||
- database
|
||||
- typesense
|
||||
|
||||
immich-machine-learning:
|
||||
container_name: immich_machine_learning
|
||||
@@ -30,18 +31,20 @@ services:
|
||||
build:
|
||||
context: ../machine-learning
|
||||
dockerfile: Dockerfile
|
||||
target: builder
|
||||
command: npm run start:dev
|
||||
command: python main.py
|
||||
ports:
|
||||
- 3003:3003
|
||||
volumes:
|
||||
- ../machine-learning:/usr/src/app
|
||||
- ../machine-learning/src:/usr/src/app
|
||||
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
||||
- /usr/src/app/node_modules
|
||||
- model-cache:/cache
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
depends_on:
|
||||
- database
|
||||
restart: always
|
||||
|
||||
immich-microservices:
|
||||
container_name: immich_microservices
|
||||
@@ -62,6 +65,7 @@ services:
|
||||
depends_on:
|
||||
- database
|
||||
- immich-server
|
||||
- typesense
|
||||
|
||||
immich-web:
|
||||
container_name: immich_web
|
||||
@@ -87,6 +91,17 @@ services:
|
||||
depends_on:
|
||||
- immich-server
|
||||
|
||||
typesense:
|
||||
container_name: immich_typesense
|
||||
image: typesense/typesense:0.24.0
|
||||
environment:
|
||||
- TYPESENSE_API_KEY=${TYPESENSE_API_KEY}
|
||||
- TYPESENSE_DATA_DIR=/data
|
||||
logging:
|
||||
driver: none
|
||||
volumes:
|
||||
- tsdata:/data
|
||||
|
||||
redis:
|
||||
container_name: immich_redis
|
||||
image: redis:6.2
|
||||
@@ -126,3 +141,5 @@ services:
|
||||
|
||||
volumes:
|
||||
pgdata:
|
||||
model-cache:
|
||||
tsdata:
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
immich-server:
|
||||
container_name: immich_server
|
||||
image: altran1502/immich-server:staging
|
||||
entrypoint: ["/bin/sh", "./start-server.sh"]
|
||||
volumes:
|
||||
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
depends_on:
|
||||
- redis
|
||||
- database
|
||||
restart: always
|
||||
|
||||
immich-microservices:
|
||||
container_name: immich_microservices
|
||||
image: altran1502/immich-server:staging
|
||||
entrypoint: ["/bin/sh", "./start-microservices.sh"]
|
||||
volumes:
|
||||
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
depends_on:
|
||||
- redis
|
||||
- database
|
||||
restart: always
|
||||
|
||||
immich-machine-learning:
|
||||
container_name: immich_machine_learning
|
||||
image: altran1502/immich-machine-learning:staging
|
||||
entrypoint: ["/bin/sh", "./entrypoint.sh"]
|
||||
volumes:
|
||||
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
depends_on:
|
||||
- database
|
||||
restart: always
|
||||
|
||||
immich-web:
|
||||
container_name: immich_web
|
||||
image: altran1502/immich-web:staging
|
||||
entrypoint: ["/bin/sh", "./entrypoint.sh"]
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
# Rename these values for svelte public interface
|
||||
- PUBLIC_IMMICH_SERVER_URL=${IMMICH_SERVER_URL}
|
||||
- PUBLIC_IMMICH_API_URL_EXTERNAL=${IMMICH_API_URL_EXTERNAL}
|
||||
restart: always
|
||||
|
||||
redis:
|
||||
container_name: immich_redis
|
||||
image: redis:6.2
|
||||
restart: always
|
||||
|
||||
database:
|
||||
container_name: immich_postgres
|
||||
image: postgres:14
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||||
POSTGRES_USER: ${DB_USERNAME}
|
||||
POSTGRES_DB: ${DB_DATABASE_NAME}
|
||||
PG_DATA: /var/lib/postgresql/data
|
||||
volumes:
|
||||
- pgdata:/var/lib/postgresql/data
|
||||
restart: always
|
||||
|
||||
immich-proxy:
|
||||
container_name: immich_proxy
|
||||
image: altran1502/immich-proxy:staging
|
||||
environment:
|
||||
# Make sure these values get passed through from the env file
|
||||
- IMMICH_SERVER_URL
|
||||
- IMMICH_WEB_URL
|
||||
ports:
|
||||
- 2283:8080
|
||||
logging:
|
||||
driver: none
|
||||
depends_on:
|
||||
- immich-server
|
||||
restart: always
|
||||
|
||||
volumes:
|
||||
pgdata:
|
||||
@@ -1,4 +1,4 @@
|
||||
version: '3.8'
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
immich-server-test:
|
||||
@@ -9,7 +9,7 @@ services:
|
||||
target: builder
|
||||
command: npm run test:e2e
|
||||
expose:
|
||||
- '3000'
|
||||
- "3000"
|
||||
volumes:
|
||||
- ../server:/usr/src/app
|
||||
- /usr/src/app/node_modules
|
||||
@@ -17,6 +17,7 @@ services:
|
||||
- .env.test
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
- TYPESENSE_ENABLED=false
|
||||
depends_on:
|
||||
- immich-redis-test
|
||||
- immich-database-test
|
||||
|
||||
@@ -3,56 +3,62 @@ version: "3.8"
|
||||
services:
|
||||
immich-server:
|
||||
container_name: immich_server
|
||||
image: altran1502/immich-server:release
|
||||
image: ghcr.io/immich-app/immich-server:release
|
||||
entrypoint: ["/bin/sh", "./start-server.sh"]
|
||||
volumes:
|
||||
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
depends_on:
|
||||
- redis
|
||||
- database
|
||||
- typesense
|
||||
restart: always
|
||||
|
||||
immich-microservices:
|
||||
container_name: immich_microservices
|
||||
image: altran1502/immich-server:release
|
||||
image: ghcr.io/immich-app/immich-server:release
|
||||
entrypoint: ["/bin/sh", "./start-microservices.sh"]
|
||||
volumes:
|
||||
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
depends_on:
|
||||
- redis
|
||||
- database
|
||||
- typesense
|
||||
restart: always
|
||||
|
||||
immich-machine-learning:
|
||||
container_name: immich_machine_learning
|
||||
image: altran1502/immich-machine-learning:release
|
||||
entrypoint: ["/bin/sh", "./entrypoint.sh"]
|
||||
image: ghcr.io/immich-app/immich-machine-learning:release
|
||||
volumes:
|
||||
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
||||
- model-cache:/cache
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
depends_on:
|
||||
- database
|
||||
restart: always
|
||||
|
||||
immich-web:
|
||||
container_name: immich_web
|
||||
image: altran1502/immich-web:release
|
||||
image: ghcr.io/immich-app/immich-web:release
|
||||
entrypoint: ["/bin/sh", "./entrypoint.sh"]
|
||||
env_file:
|
||||
- .env
|
||||
restart: always
|
||||
|
||||
typesense:
|
||||
container_name: immich_typesense
|
||||
image: typesense/typesense:0.24.0
|
||||
environment:
|
||||
- TYPESENSE_API_KEY=${TYPESENSE_API_KEY}
|
||||
- TYPESENSE_DATA_DIR=/data
|
||||
logging:
|
||||
driver: none
|
||||
volumes:
|
||||
- tsdata:/data
|
||||
restart: always
|
||||
|
||||
redis:
|
||||
container_name: immich_redis
|
||||
image: redis:6.2
|
||||
@@ -74,7 +80,7 @@ services:
|
||||
|
||||
immich-proxy:
|
||||
container_name: immich_proxy
|
||||
image: altran1502/immich-proxy:release
|
||||
image: ghcr.io/immich-app/immich-proxy:release
|
||||
environment:
|
||||
# Make sure these values get passed through from the env file
|
||||
- IMMICH_SERVER_URL
|
||||
@@ -89,3 +95,5 @@ services:
|
||||
|
||||
volumes:
|
||||
pgdata:
|
||||
model-cache:
|
||||
tsdata:
|
||||
|
||||
@@ -16,9 +16,20 @@ DB_DATABASE_NAME=immich
|
||||
|
||||
REDIS_HOSTNAME=immich_redis
|
||||
|
||||
# REDIS_URL will be used to pass custom options to ioredis.
|
||||
# Example for Sentinel
|
||||
# {"sentinels":[{"host":"redis-sentinel-node-0","port":26379},{"host":"redis-sentinel-node-1","port":26379},{"host":"redis-sentinel-node-2","port":26379}],"name":"redis-sentinel"}
|
||||
# REDIS_URL=ioredis://eyJzZW50aW5lbHMiOlt7Imhvc3QiOiJyZWRpcy1zZW50aW5lbDEiLCJwb3J0IjoyNjM3OX0seyJob3N0IjoicmVkaXMtc2VudGluZWwyIiwicG9ydCI6MjYzNzl9XSwibmFtZSI6Im15bWFzdGVyIn0=
|
||||
|
||||
# Optional Redis settings:
|
||||
|
||||
# Note: these parameters are not automatically passed to the Redis Container
|
||||
# to do so, please edit the docker-compose.yml file as well. Redis is not configured
|
||||
# via environment variables, only redis.conf or the command line
|
||||
|
||||
# REDIS_PORT=6379
|
||||
# REDIS_DBINDEX=0
|
||||
# REDIS_USERNAME=
|
||||
# REDIS_PASSWORD=
|
||||
# REDIS_SOCKET=
|
||||
|
||||
@@ -30,6 +41,21 @@ REDIS_HOSTNAME=immich_redis
|
||||
|
||||
UPLOAD_LOCATION=absolute_location_on_your_machine_where_you_want_to_store_the_backup
|
||||
|
||||
|
||||
###################################################################################
|
||||
# Typesense
|
||||
###################################################################################
|
||||
TYPESENSE_API_KEY=some-random-text
|
||||
# TYPESENSE_ENABLED=false
|
||||
# TYPESENSE_URL uses base64 encoding for the nodes json.
|
||||
# Example JSON that was used:
|
||||
# [
|
||||
# { 'host': 'typesense-1.example.net', 'port': '443', 'protocol': 'https' },
|
||||
# { 'host': 'typesense-2.example.net', 'port': '443', 'protocol': 'https' },
|
||||
# { 'host': 'typesense-3.example.net', 'port': '443', 'protocol': 'https' },
|
||||
# ]
|
||||
# TYPESENSE_URL=ha://WwogICAgeyAnaG9zdCc6ICd0eXBlc2Vuc2UtMS5leGFtcGxlLm5ldCcsICdwb3J0JzogJzQ0MycsICdwcm90b2NvbCc6ICdodHRwcycgfSwKICAgIHsgJ2hvc3QnOiAndHlwZXNlbnNlLTIuZXhhbXBsZS5uZXQnLCAncG9ydCc6ICc0NDMnLCAncHJvdG9jb2wnOiAnaHR0cHMnIH0sCiAgICB7ICdob3N0JzogJ3R5cGVzZW5zZS0zLmV4YW1wbGUubmV0JywgJ3BvcnQnOiAnNDQzJywgJ3Byb3RvY29sJzogJ2h0dHBzJyB9LApd
|
||||
|
||||
###################################################################################
|
||||
# Reverse Geocoding
|
||||
#
|
||||
@@ -76,4 +102,4 @@ IMMICH_MACHINE_LEARNING_URL=http://immich-machine-learning:3003
|
||||
# Examples: http://localhost:3001, http://immich-api.example.com, etc
|
||||
####################################################################################
|
||||
|
||||
#IMMICH_API_URL_EXTERNAL=http://localhost:3001
|
||||
#IMMICH_API_URL_EXTERNAL=http://localhost:3001
|
||||
|
||||
@@ -14,16 +14,38 @@ sidebar_position: 7
|
||||
|
||||
### How can I sync an existing directory with Immich's server?
|
||||
|
||||
Immich doesn't have the mechanism to sync an existing directory with the server. There is however, a helper CLI tool to help you bulk upload the existing photos and videos to the server. You can find the guide to use the CLI tool [here](/docs/features/bulk-upload.md).
|
||||
Immich doesn't have two-way synchronization ([yet](https://github.com/immich-app/immich/discussions/1006)), but the [command line tool](/docs/features/bulk-upload.md) can bulk upload items from a directory to Immich.
|
||||
|
||||
### Why doesn't Immich watch an existing photo gallery directory?
|
||||
|
||||
The initial approach of Immich is to become a backup tool, primarily for mobile device usage. Thus, all the assets must be uploaded from the mobile client. The app was architectured to perform that job well.
|
||||
|
||||
### Why does my uploaded photo show up with the wrong date or time in Immich?
|
||||
|
||||
When a photo is initially uploaded Immich uses the create date of the file to determine where it belongs in the timeline. After that, background jobs will run that extract [exif metadata](https://en.wikipedia.org/wiki/Exif), including the CreateDate, to provide a more accurate date for the photo. If that is not available it will fallback to the modified date. If you want to ensure your photo has the right date, check the exif metadata before uploading.
|
||||
|
||||
If the timezone is incorrect in an uploaded photo, check the ``DateTimeOriginal`` exif field of the uploaded file. Immich uses the very competent library [exiftool-vendored.js](https://github.com/photostructure/exiftool-vendored.js#dates) to handle timezone parsing, but in some cases (like photos taken with DSLR cameras) it has to fallback on the local timezone. If you are using docker, this fallback will be UTC. (Note that even the photo backup app that can't be named [has the same bug!](https://photo.stackexchange.com/a/126978)) In Immich, it is possible to change this assumed fallback timezone system-wide by setting the timezone in the microservices docker container. You might need to run the "Extract Metadata" job after to effect the change.
|
||||
|
||||
As an example, the following modification of ```docker-compose.yml``` will set the timezone of the microservices container to be ``Europe/Stockholm``
|
||||
|
||||
```
|
||||
environment:
|
||||
- TZ=Europe/Stockholm # <---- Add this line in the microservices config
|
||||
```
|
||||
|
||||
### Why are only photos and not videos being uploaded to Immich?
|
||||
This often happens when using a reverse proxy or cloudflare tunnel in front of Immich. Make sure to set your reverse proxy to allow large POST requests. In `nginx`, set `client_max_body_size 50000M;` or similar. Cloudflare tunnels are limited to 100 mb file sizes.
|
||||
|
||||
### Why is Immich slow on low-memory systems like the Raspberry Pi?
|
||||
Immich uses optional machine-learning features to enhance search results. This feature, however, can be too heavy to run on a Raspberry Pi. To disable machine learning, comment out the `immich-machine-learning` section of your docker-compose.yml and set `IMMICH_MACHINE_LEARNING_URL=false` in your .env file.
|
||||
|
||||
### What happens to existing files after I choose a new [Storage Template](/docs/administration/storage-template.mdx)?
|
||||
|
||||
Template changes will only apply to new assets. To retroactively apply the template to previously uploaded assets, run the Storage Migration Job, available on the [Jobs](/docs/administration/jobs.md) page.
|
||||
|
||||
### In the uploads folder, why are photos stored in the wrong date?
|
||||
This is fixed by running the storage migration job.
|
||||
|
||||
### Why is object detection not very good?
|
||||
|
||||
The model we used for machine learning is a prebuilt model, so the accuracy is not very good. It will hopefully be replaced with a better solution in the future.
|
||||
@@ -58,3 +80,7 @@ docker-compose down -v
|
||||
```
|
||||
|
||||
After removing the the containers and volumes, the **Files** can be cleaned up (if necessary) from the `UPLOAD_LOCATION` by simply deleting an unwanted files or folders.
|
||||
|
||||
### Why iOS app shows duplicate photos on the timeline while the web doesn't?
|
||||
|
||||
If you are using `My Photo Stream`, the Photos app temporarily creates duplicates of photos taken in the last 30 days. These photos are included in the `Recents` album and thus shown up twice. To fix this, you can disable `My Photo Stream` in the native Photos app or choose a different album in the backup screen in Immich.
|
||||
BIN
docs/docs/administration/img/admin-jobs.png
Normal file
|
After Width: | Height: | Size: 111 KiB |
@@ -2,22 +2,8 @@
|
||||
|
||||
Several Immich functionalities are implemented as jobs, which run in the background. To view the status of a job navigate to the Administration Screen, and then the `Jobs` page.
|
||||
|
||||

|
||||
|
||||
## Generate Thumbnails
|
||||
|
||||

|
||||
|
||||
|
||||
## Extract Exif
|
||||
|
||||

|
||||
|
||||
## Detect Objects
|
||||
|
||||

|
||||
|
||||
## Storage Migration
|
||||
|
||||
This job can be run after changing the [Storage Template](/docs/administration/storage-template.mdx), in order to apply the change to the existing library.
|
||||
|
||||

|
||||
:::info
|
||||
Storage Migration job can be run after changing the [Storage Template](/docs/administration/storage-template.mdx), in order to apply the change to the existing library.
|
||||
:::
|
||||
|
||||
22
docs/docs/administration/reverse-proxy.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Reverse Proxy
|
||||
|
||||
When deploying Immich it is important to understand that a reverse proxy is required in front of the server and web container. The reverse proxy acts as an intermediary between the user and container, forwarding requests to the correct container based on the URL path.
|
||||
|
||||
## Default Reverse Proxy
|
||||
|
||||
Immich provides a default nginx reverse proxy preconfigured to perform the correct routing and set the necessary headers for the server and web container to use. These headers are crucial to redirect to the correct URL and determine the client's IP address.
|
||||
|
||||
## Using a Different Reverse Proxy
|
||||
|
||||
While the reverse proxy provided by Immich works well for basic deployments, some users may want to use a different reverse proxy. Fortunately, Immich is flexible enough to accommodate different reverse proxies. Users can either:
|
||||
|
||||
1. Add another reverse proxy on top of Immich's reverse proxy
|
||||
2. Completely replace the default reverse proxy
|
||||
|
||||
## Adding a Custom Reverse Proxy
|
||||
|
||||
Users can deploy a custom reverse proxy that forwards requests to Immich's reverse proxy. This way, the new reverse proxy can handle TLS termination, load balancing, or other advanced features, while still delegating routing decisions to Immich's reverse proxy. All reverse proxies between Immich and the user must forward all headers and set the `Host`, `X-Forwarded-Host`, `X-Forwarded-Proto` and `X-Forwarded-For` headers to their appropriate values. By following these practices, you ensure that all custom reverse proxies are fully compatible with Immich.
|
||||
|
||||
## Replacing the Default Reverse Proxy
|
||||
|
||||
Replacing Immich's default reverse proxy is an advanced deployment and support may be limited. When replacing Immich's default proxy it is important to ensure that requests to `/api/*` are routed to the server container and all other requests to the web container. Additionally, the previously mentioned headers should be configured accordingly. You may find our [nginx configuration file](https://github.com/immich-app/immich/blob/main/nginx/templates/default.conf.template) a helpful reference.
|
||||
@@ -20,7 +20,7 @@ Immich is a full-stack [TypeScript](https://www.typescriptlang.org/) application
|
||||
### Web
|
||||
|
||||
- [SvelteKit](https://kit.svelte.dev/)
|
||||
- [tailwindcss](https://tailwindcss.com/)
|
||||
- [Tailwindcss](https://tailwindcss.com/)
|
||||
|
||||
### Server
|
||||
|
||||
@@ -28,11 +28,14 @@ Immich is a full-stack [TypeScript](https://www.typescriptlang.org/) application
|
||||
- [Nest.js](https://nestjs.com/)
|
||||
- [TypeORM](https://typeorm.io/) for database management.
|
||||
- [Jest](https://jestjs.io/) for testing.
|
||||
- [Python](https://www.python.org/) for Machine Learning.
|
||||
|
||||
### Database
|
||||
|
||||
- [PostgreSQL](https://www.postgresql.org/)
|
||||
- [Redis](https://redis.io/) for job queuing.
|
||||
- [Typesense](https://typesense.org/) for search.
|
||||
|
||||
|
||||
### Web Server
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 691 KiB After Width: | Height: | Size: 570 KiB |
@@ -43,6 +43,18 @@ The mobile app `(/mobile)` will required Flutter toolchain to be installed on yo
|
||||
|
||||
Please refer to the [Flutter's official documentation](https://flutter.dev/docs/get-started/install) for more information on setting up the toolchain on your machine.
|
||||
|
||||
### Connect to a remote backend
|
||||
|
||||
If you only want to do web development connected to an existing, remote backend, follow these steps:
|
||||
|
||||
1. Enter the web directory - `cd web/`
|
||||
2. Install web dependencies - `npm i`
|
||||
3. Start the web development server
|
||||
|
||||
```
|
||||
PUBLIC_IMMICH_SERVER_URL=https://demo.immich.app/api npm run dev
|
||||
```
|
||||
|
||||
## IDE setup
|
||||
|
||||
### Lint / format extensions
|
||||
|
||||
@@ -4,33 +4,31 @@ A guide on how the foreground and background automatic backup works.
|
||||
|
||||
<img src={require('./img/background-foreground-backup.png').default} width="50%" title="Foreground&Background Backup" />
|
||||
|
||||
On iOS, there is only one option for automatic backup
|
||||
|
||||
- [Automatic Backup](#automatic-backup)
|
||||
- [Foreground backup](#foreground-backup)
|
||||
|
||||
On Android, there are two options for automatic backup
|
||||
|
||||
- [Automatic Backup](#automatic-backup)
|
||||
- [Foreground backup](#foreground-backup)
|
||||
- [Background backup](#background-backup)
|
||||
|
||||
## Foreground backup
|
||||
|
||||
If foreground backup is enabled: whenever the app is opened or resumed, it will check if any photos or videos in the selected album(s) have yet to be uploaded to the cloud (the remainder count). If there are any, they will be uploaded.
|
||||
|
||||
## Background backup
|
||||
|
||||
Background backup is only available on Android thanks to the contribution effort of [@zoodyy](https://github.com/zoodyy).
|
||||
Background backup is available thanks to the contribution effort of [@zoodyy](https://github.com/zoodyy) and [@martyfuhry](https://github.com/martyfuhry).
|
||||
|
||||
If background backup is enabled. The app will periodically check if there are any new photos or videos in the selected album(s) to be uploaded to the cloud. If there are, it will upload them to the cloud in the background.
|
||||
|
||||
A native Android notification shows up when the background upload is in progress. You can further customize the notification by going to the app's settings.
|
||||
|
||||
:::info Note
|
||||
|
||||
#### General
|
||||
- The app must be in the background for the backup worker to start running.
|
||||
- It is a well-known problem that some Android models are very strict with battery optimization settings, which can cause a problem with the background worker. Please visit [Don't kill my app](https://dontkillmyapp.com/) for a guide on disabling this setting on your phone.
|
||||
- If you reopen the app and the first page you see is the backup page, the counts will not reflect the background uploaded result. You have to navigate out of the page and come back to see the updated counts.
|
||||
|
||||
#### Android
|
||||
- It is a well-known problem that some Android models are very strict with battery optimization settings, which can cause a problem with the background worker. Please visit [Don't kill my app](https://dontkillmyapp.com/) for a guide on disabling this setting on your phone.
|
||||
|
||||
#### iOS
|
||||
- You must enable **Background App Refresh** for the app to work in the background. You can enable it in the Settings app under General > Background App Refresh.
|
||||
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<img src={require('./img/background-app-refresh.png').default} width="30%" title="background-app-refresh" />
|
||||
</div>
|
||||
|
||||
:::
|
||||
|
||||
@@ -17,23 +17,29 @@ npm i -g immich
|
||||
|
||||
## Quick Start
|
||||
|
||||
Specify user's credentials, Immich's server address and port, and the directory you would like to upload videos/photos from.
|
||||
Specify user's credential, Immich's server address and port and the directory you would like to upload videos/photos from.
|
||||
|
||||
```bash
|
||||
immich upload --key HFEJ38DNSDUEG --server http://192.168.1.216:2283/api -d your/target/directory
|
||||
```
|
||||
immich upload --key HFEJ38DNSDUEG --server http://192.168.1.216:2283/api file1.jpg file2.jpg
|
||||
```
|
||||
|
||||
By default, subfolders are not included. To upload a directory including subfolder, use the --recursive option:
|
||||
|
||||
```
|
||||
immich upload --key HFEJ38DNSDUEG --server http://192.168.1.216:2283/api --recursive directory/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Parameters
|
||||
### Options
|
||||
|
||||
| Parameter | Description |
|
||||
| ---------------- | ------------------------------------------------------------------- |
|
||||
| --yes / -y | Assume yes on all interactive prompts |
|
||||
| --recursive / -r | Include subfolders |
|
||||
| --delete / -da | Delete local assets after upload |
|
||||
| --key / -k | User's API key |
|
||||
| --server / -s | Immich's server address |
|
||||
| --directory / -d | Directory to upload from |
|
||||
| --threads / -t | Number of threads to use (Default 5) |
|
||||
| --album/ -al | Create albums for assets based on the parent folder or a given name |
|
||||
|
||||
@@ -54,15 +60,15 @@ Be aware that as this runs inside a container, you need to mount the folder from
|
||||
|
||||
```bash title="Upload current directory"
|
||||
cd /DIRECTORY/WITH/IMAGES
|
||||
docker run -it --rm -v $(pwd):/import ghcr.io/immich-app/immich-cli:latest upload --key HFEJ38DNSDUEG --server http://192.168.1.216:2283/api
|
||||
docker run -it --rm -v "$(pwd):/import" ghcr.io/immich-app/immich-cli:latest upload --key HFEJ38DNSDUEG --server http://192.168.1.216:2283/api
|
||||
```
|
||||
|
||||
```bash title="Upload target directory"
|
||||
docker run -it --rm -v /DIRECTORY/WITH/IMAGES:/import ghcr.io/immich-app/immich-cli:latest upload --key HFEJ38DNSDUEG --server http://192.168.1.216:2283/api
|
||||
docker run -it --rm -v "/DIRECTORY/WITH/IMAGES:/import" ghcr.io/immich-app/immich-cli:latest upload --key HFEJ38DNSDUEG --server http://192.168.1.216:2283/api
|
||||
```
|
||||
|
||||
```bash title="Create an alias"
|
||||
alias immich="docker run -it --rm -v $(pwd):/import ghcr.io/immich-app/immich-cli:latest"
|
||||
alias immich='docker run -it --rm -v "$(pwd):/import" ghcr.io/immich-app/immich-cli:latest'
|
||||
immich upload --key HFEJ38DNSDUEG --server http://192.168.1.216:2283/api
|
||||
```
|
||||
|
||||
@@ -73,7 +79,7 @@ If you are running the CLI container on the same machine as your Immich server,
|
||||
3. Use `--server http://immich-server:3001/` for the upload command instead of the external address.
|
||||
|
||||
```bash title="Upload to internal address"
|
||||
docker run --network immich_default -it --rm -v $(pwd):/import ghcr.io/immich-app/immich-cli:latest upload --key HFEJ38DNSDUEG --server http://immich-server:3001/
|
||||
docker run --network immich_default -it --rm -v "$(pwd):/import" ghcr.io/immich-app/immich-cli:latest upload --key HFEJ38DNSDUEG --server http://immich-server:3001/
|
||||
```
|
||||
:::
|
||||
|
||||
@@ -92,5 +98,5 @@ npm run build
|
||||
```
|
||||
|
||||
```bash title="Run the command"
|
||||
node bin/index.js upload --key HFEJ38DNSDUEG --server http://192.168.1.216:2283/api -d your/target/directory
|
||||
node bin/index.js upload --key HFEJ38DNSDUEG --server http://192.168.1.216:2283/api --recursive your/asset/directory
|
||||
```
|
||||
|
||||
BIN
docs/docs/features/img/background-app-refresh.png
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
docs/docs/features/img/search-ex-2.webp
Normal file
|
After Width: | Height: | Size: 162 KiB |
BIN
docs/docs/features/img/search-ex-3.webp
Normal file
|
After Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 16 KiB |
@@ -1,16 +1,20 @@
|
||||
# Search
|
||||
|
||||
:::warning Work In Progress
|
||||
Search is work-in-progress and subject to change. Stay tuned!
|
||||
:::
|
||||
Immich uses Typesense as the primary search database to enable high performance search mechanism.
|
||||
|
||||
## Search by Place
|
||||
Typesense is a powerful search engine that can be integrated with popular natural language processing (NLP) models like CLIP and SBERT to provide highly accurate and relevant search results. Here are some benefits of using Typesense integrated search for CLIP and SBERT:
|
||||
|
||||
:::info
|
||||
Searching is currently only implemented in the [Mobile App](/docs/features/mobile-app.mdx)
|
||||
:::
|
||||
Improved Search Accuracy: Typesense uses a combination of indexing, querying, and ranking algorithms to quickly and accurately retrieve relevant search results. When integrated with CLIP and SBERT, Typesense can leverage the semantic understanding and deep learning capabilities of these models to further improve the accuracy of search results.
|
||||
|
||||
Searching by the name of a city, state, or country is possible for assets with geolocation data and successful [Reverse Geocoding](/docs/features/reverse-geocoding.md).
|
||||
Faster Search Response Times: Typesense is optimized for lightning-fast search response times, making it ideal for applications that require near-instantaneous search results. By integrating with CLIP and SBERT, Typesense can reduce the time required to process complex search queries, making it even faster and more efficient.
|
||||
|
||||
<img src={require('./img/reverse-geocoding-mobile1.png').default} width='33%' title='Reverse Geocoding' />
|
||||
<img src={require('./img/reverse-geocoding-mobile2.png').default} width='33%' title='Reverse Geocoding' />
|
||||
Enhanced Semantic Search Capabilities: CLIP and SBERT are powerful NLP models that can extract the semantic meaning from text, enabling more nuanced search queries. By integrating with Typesense, these models can help to improve the accuracy of semantic search, enabling users to find the most relevant results based on the true meaning of their query.
|
||||
|
||||
Greater Search Flexibility: Typesense provides flexible search capabilities, including fuzzy search, partial search, enabling users to find the information they need quickly and easily. When integrated with CLIP and SBERT, Typesense can offer even greater flexibility, allowing users to refine their search queries using natural language and providing more accurate and relevant results.
|
||||
|
||||
(Generated by Chat-GPT4)
|
||||
|
||||
Some search examples:
|
||||
<img src={require('./img/search-ex-2.webp').default} title='Search Example 1' />
|
||||
|
||||
<img src={require('./img/search-ex-3.webp').default} title='Search Example 2' />
|
||||
|
||||
@@ -8,9 +8,14 @@ Docker Compose is the recommended method to run Immich in production. Below are
|
||||
|
||||
### Step 1 - Download the required files
|
||||
|
||||
Download [`docker-compose.yml`][compose-file] [`example.env`][env-file].
|
||||
Create a directory of your choice (e.g. `./immich-app`) to hold the `docker-compose.yml` and `.env` files.
|
||||
|
||||
From a directory of your choice (e.g. `./immich-app`) run the following commands:
|
||||
```bash title="Move to the directory you created"
|
||||
mkdir ./immich-app
|
||||
cd ./immich-app
|
||||
```
|
||||
|
||||
Download [`docker-compose.yml`][compose-file] and [`example.env`][env-file], either by running the following commands:
|
||||
|
||||
```bash title="Get docker-compose.yml file"
|
||||
wget https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
|
||||
@@ -20,6 +25,10 @@ wget https://github.com/immich-app/immich/releases/latest/download/docker-compos
|
||||
wget -O .env https://github.com/immich-app/immich/releases/latest/download/example.env
|
||||
```
|
||||
|
||||
or by downloading from your browser and moving the files to the directory that you created.
|
||||
|
||||
Note: If you downloaded the files from your browser, also ensure that you rename `example.env` to `.env`.
|
||||
|
||||
### Step 2 - Populate the .env file with custom values
|
||||
|
||||
<details>
|
||||
@@ -46,29 +55,43 @@ DB_DATABASE_NAME=immich
|
||||
REDIS_HOSTNAME=immich_redis
|
||||
|
||||
# Optional Redis settings:
|
||||
|
||||
# Note: these parameters are not automatically passed to the Redis Container
|
||||
# to do so, please edit the docker-compose.yml file as well. Redis is not configured
|
||||
# via environment variables, only redis.conf or the command line
|
||||
|
||||
# REDIS_PORT=6379
|
||||
# REDIS_DBINDEX=0
|
||||
# REDIS_PASSWORD=
|
||||
# REDIS_SOCKET=
|
||||
|
||||
###################################################################################
|
||||
# Upload File Config
|
||||
# Upload File Location
|
||||
#
|
||||
# This is the location where uploaded files are stored.
|
||||
###################################################################################
|
||||
|
||||
UPLOAD_LOCATION=absolute_location_on_your_machine_where_you_want_to_store_the_backup
|
||||
|
||||
|
||||
###################################################################################
|
||||
# Log message level - [simple|verbose]
|
||||
###################################################################################
|
||||
|
||||
LOG_LEVEL=simple
|
||||
|
||||
###################################################################################
|
||||
# Typesense
|
||||
###################################################################################
|
||||
# TYPESENSE_ENABLED=false
|
||||
TYPESENSE_API_KEY=some-random-text
|
||||
# TYPESENSE_HOST: typesense
|
||||
# TYPESENSE_PORT: 8108
|
||||
# TYPESENSE_PROTOCOL: http
|
||||
|
||||
###################################################################################
|
||||
# Reverse Geocoding
|
||||
####################################################################################
|
||||
|
||||
# DISABLE_REVERSE_GEOCODING=false
|
||||
|
||||
#
|
||||
# Reverse geocoding is done locally which has a small impact on memory usage
|
||||
# This memory usage can be altered by changing the REVERSE_GEOCODING_PRECISION variable
|
||||
# This ranges from 0-3 with 3 being the most precise
|
||||
@@ -76,28 +99,58 @@ LOG_LEVEL=simple
|
||||
# 2 - Cities > 1000 population: ~150MB RAM
|
||||
# 1 - Cities > 5000 population: ~80MB RAM
|
||||
# 0 - Cities > 15000 population: ~40MB RAM
|
||||
####################################################################################
|
||||
|
||||
# DISABLE_REVERSE_GEOCODING=false
|
||||
# REVERSE_GEOCODING_PRECISION=3
|
||||
|
||||
####################################################################################
|
||||
# WEB - Optional
|
||||
#
|
||||
# Custom message on the login page, should be written in HTML form.
|
||||
# For example:
|
||||
# PUBLIC_LOGIN_PAGE_MESSAGE="This is a demo instance of Immich.<br><br>Email: <i>demo@demo.de</i><br>Password: <i>demo</i>"
|
||||
####################################################################################
|
||||
|
||||
# Custom message on the login page, should be written in HTML form.
|
||||
# For example PUBLIC_LOGIN_PAGE_MESSAGE="This is a demo instance of Immich.<br><br>Email: <i>demo@demo.de</i><br>Password: <i>demo</i>"
|
||||
|
||||
PUBLIC_LOGIN_PAGE_MESSAGE="My Family Photos and Videos Backup Server"
|
||||
|
||||
####################################################################################
|
||||
# Alternative Service Addresses - Optional
|
||||
#
|
||||
# This is an advanced feature for users who may be running their immich services on different hosts.
|
||||
# It will not change which address or port that services bind to within their containers, but it will change where other services look for their peers.
|
||||
# Note: immich-microservices is bound to 3002, but no references are made
|
||||
####################################################################################
|
||||
|
||||
IMMICH_WEB_URL=http://immich-web:3000
|
||||
IMMICH_SERVER_URL=http://immich-server:3001
|
||||
IMMICH_MACHINE_LEARNING_URL=http://immich-machine-learning:3003
|
||||
|
||||
####################################################################################
|
||||
# Alternative API's External Address - Optional
|
||||
#
|
||||
# This is an advanced feature used to control the public server endpoint returned to clients during Well-known discovery.
|
||||
# You should only use this if you want mobile apps to access the immich API over a custom URL. Do not include trailing slash.
|
||||
# NOTE: At this time, the web app will not be affected by this setting and will continue to use the relative path: /api
|
||||
# Examples: http://localhost:3001, http://immich-api.example.com, etc
|
||||
####################################################################################
|
||||
|
||||
#IMMICH_API_URL_EXTERNAL=http://localhost:3001
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
- Populate custom database information if necessary.
|
||||
- Populate `UPLOAD_LOCATION` with your preferred location for storing backup assets.
|
||||
- Consider changing `DB_PASSWORD` to something randomly generated
|
||||
- Consider changing `TYPESENSE_API_KEY` to something randomly generated
|
||||
|
||||
### Step 3 - Start the containers
|
||||
|
||||
From the directory you created in Step 1, (which should now contain your customized `docker-compose.yml` and `.env` files) run `docker-compose up -d`.
|
||||
|
||||
```bash title="Start the containers using docker compose command"
|
||||
docker-compose up -d # or `docker compose up -d` based on your docker-compose version
|
||||
docker-compose up -d # or `docker compose up -d` based on your docker-compose version
|
||||
```
|
||||
|
||||
:::tip
|
||||
@@ -109,7 +162,7 @@ For more information on how to use the application, please refer to the [Post In
|
||||
When a new version of Immich is [released](https://github.com/immich-app/immich/releases), the application can be upgraded with the following commands, run in the directory with the `docker-compose.yml` file:
|
||||
|
||||
```bash title="Upgrade Immich"
|
||||
docker-compose pull && docker-compose up -d # Or `docker compose`
|
||||
docker-compose pull && docker-compose up -d # Or `docker compose up -d`
|
||||
```
|
||||
|
||||
:::caution Automatic Updates
|
||||
|
||||
@@ -4,12 +4,12 @@ sidebar_position: 40
|
||||
|
||||
# Kubernetes
|
||||
|
||||
You can deploy Immich on Kubernetes using [the official Helm chart](https://github.com/immich-app/immich-charts/tree/main/charts/apps/immich).
|
||||
You can deploy Immich on Kubernetes using [the official Helm chart](https://github.com/immich-app/immich-charts/tree/main/charts/immich).
|
||||
|
||||
If you want examples of how other people run Immich on Kubernetes, using the official chart or otherwise, you can find them at https://nanne.dev/k8s-at-home-search/#/immich.
|
||||
|
||||
:::caution DNS in Alpine containers
|
||||
Immich makes use of Alpine container images. These can encounter [a DNS resolution bug](https://stackoverflow.com/a/65593511) on Kubernetes clusters if the host
|
||||
Immich makes use of Alpine container images. These can encounter [a DNS resolution bug](https://stackoverflow.com/a/65593511) on Kubernetes clusters if the host
|
||||
nodes have a search domain set, like:
|
||||
|
||||
```
|
||||
@@ -18,7 +18,7 @@ search home.lan
|
||||
nameserver 192.168.1.1
|
||||
```
|
||||
|
||||
When you encounter this bug, it will cause the immich-microservices to crash on startup because it cannot download
|
||||
the geocoder data. This can be solved in one of two ways: Either reconfigure your nodes to remove the searchdomain from
|
||||
When you encounter this bug, it will cause the immich-microservices to crash on startup because it cannot download
|
||||
the geocoder data. This can be solved in one of two ways: Either reconfigure your nodes to remove the searchdomain from
|
||||
`resolv.conf`, or set the `DISABLE_REVERSE_GEOCODING` environment variable for Immich to `true` to disable the geocoder.
|
||||
:::
|
||||
:::
|
||||
|
||||
@@ -20,28 +20,3 @@ You can also use Podman to run the application. However, additional configuratio
|
||||
- **OS**: Preferred unix-based operating system (Ubuntu, Debian, MacOS, etc). Windows works too, with [Docker Desktop on Windows](https://docs.docker.com/desktop/install/windows-install/)
|
||||
- **RAM**: At least 2GB, preferred 4GB.
|
||||
- **CPU**: At least 2 cores, preferred 4 cores.
|
||||
|
||||
:::info Machine Learning on older CPU
|
||||
|
||||
The TensorFlow version used by Immich doesn't run on older CPU architectures. It requires a CPU with AVX and AVX2 instruction sets. If you encounter the error `illegal instruction core dump` check your CPU flags with the command below and make sure you see `avx` and `avx2`:
|
||||
|
||||
```bash
|
||||
grep -E 'avx2?' /proc/cpuinfo
|
||||
```
|
||||
|
||||
#### Promox
|
||||
|
||||
If you are running virtualization in Proxmox, the CPU type of the VM is probably configured incorrectly.
|
||||
|
||||
You need to change the CPU type from `kvm64` to `host` under VMs hardware tab.
|
||||
|
||||
`Hardware > Processors > Edit > Advanced > Type (dropdown menu) > host`
|
||||
|
||||
#### Other platforms
|
||||
|
||||
You can use the machine learning image that is built for Non-AVX CPU. The image is community maintained and can be found in the repository below
|
||||
|
||||
https://github.com/bertmelis/immich-machine-learning-no-avx
|
||||
|
||||
Otherwise, you can safely remove the `immich-machine-learning` service if you do not intend to use Immich's object detection features. Simply remove or comment out the declaration of the service in your compose file.
|
||||
:::
|
||||
|
||||
@@ -18,7 +18,7 @@ Immich can easily be installed and updated on Unraid via:
|
||||
|
||||
In order to install Immich from the Unraid CA, you will need an existing Redis and PostgreSQL 14 container, If you do not already have Redis or PostgreSQL you can install them from the Unraid CA, just make sure you choose PostgreSQL **14**.
|
||||
|
||||
Once you have Redis and PostgreSQL running, search for Immich on the Unraid CA, Choose either of the templates listed and fill out the example variables.
|
||||
Once you have Redis and PostgreSQL running, search for Immich on the Unraid CA, choose either of the templates listed and fill out the example variables.
|
||||
|
||||
For more information about setting up the community image see [here](https://github.com/imagegenius/docker-immich#application-setup)
|
||||
|
||||
@@ -71,7 +71,7 @@ alt="Select Plugins > Compose.Manager > Add New Stack > Label it Immich"
|
||||
</details>
|
||||
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**"
|
||||
7. Past 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:
|
||||
|
||||
- `UPLOAD_LOCATION`: Create a folder in your Images Unraid share and place the **absolute** location here > For example my _"images"_ share has a folder within it called _"immich"_. If I browse to this directory in the terminal and type `pwd` the output is `/mnt/user/images/immich`. This is the exact value I need to enter as my `UPLOAD_LOCATION`
|
||||
|
||||
@@ -143,8 +143,8 @@ alt="Immich update notification"
|
||||
/>
|
||||
|
||||
1. Go to the "**Docker**" tab and scroll to the Compose section
|
||||
2. Next to Immich click the "**Update Stack**" button and Unraid will begin to update all Immmich related containers
|
||||
> Note: **Do not** select Compose Down first, it is unecessary.
|
||||
2. Next to Immich click the "**Update Stack**" button and Unraid will begin to update all Immich related containers
|
||||
> Note: **Do not** select Compose Down first, it is unnecessary.
|
||||
3. Once complete you will see a "_Connection Closed_" message, select "**Done**".
|
||||
<img
|
||||
src={require('./img/unraid11.png').default}
|
||||
|
||||
|
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 52 KiB |
@@ -1,70 +1,71 @@
|
||||
// @ts-check
|
||||
// Note: type annotations allow type checking and IDEs autocompletion
|
||||
|
||||
const lightCodeTheme = require("prism-react-renderer/themes/github");
|
||||
const darkCodeTheme = require("prism-react-renderer/themes/dracula");
|
||||
const lightCodeTheme = require('prism-react-renderer/themes/github');
|
||||
const darkCodeTheme = require('prism-react-renderer/themes/dracula');
|
||||
|
||||
/** @type {import('@docusaurus/types').Config} */
|
||||
const config = {
|
||||
title: "Immich",
|
||||
title: 'Immich',
|
||||
tagline:
|
||||
"High performance self-hosted photo and video backup solution directly from your mobile phone",
|
||||
url: "https://documentation.immich.app",
|
||||
baseUrl: "/",
|
||||
onBrokenLinks: "throw",
|
||||
onBrokenMarkdownLinks: "warn",
|
||||
favicon: "img/favicon.png",
|
||||
'High performance self-hosted photo and video backup solution directly from your mobile phone',
|
||||
url: 'https://documentation.immich.app',
|
||||
baseUrl: '/',
|
||||
onBrokenLinks: 'throw',
|
||||
onBrokenMarkdownLinks: 'warn',
|
||||
favicon: 'img/favicon.png',
|
||||
|
||||
// GitHub pages deployment config.
|
||||
// If you aren't using GitHub pages, you don't need these.
|
||||
organizationName: "immich-app", // Usually your GitHub org/user name.
|
||||
projectName: "immich", // Usually your repo name.
|
||||
deploymentBranch: "main",
|
||||
organizationName: 'immich-app', // Usually your GitHub org/user name.
|
||||
projectName: 'immich', // Usually your repo name.
|
||||
deploymentBranch: 'main',
|
||||
// Even if you don't use internalization, you can use this field to set useful
|
||||
// metadata like html lang. For example, if your site is Chinese, you may want
|
||||
// to replace "en" with "zh-Hans".
|
||||
i18n: {
|
||||
defaultLocale: "en",
|
||||
locales: ["en"],
|
||||
defaultLocale: 'en',
|
||||
locales: ['en'],
|
||||
},
|
||||
|
||||
plugins: [
|
||||
async function myPlugin(context, options) {
|
||||
return {
|
||||
name: "docusaurus-tailwindcss",
|
||||
name: 'docusaurus-tailwindcss',
|
||||
configurePostCss(postcssOptions) {
|
||||
// Appends TailwindCSS and AutoPrefixer.
|
||||
postcssOptions.plugins.push(require("tailwindcss"));
|
||||
postcssOptions.plugins.push(require("autoprefixer"));
|
||||
postcssOptions.plugins.push(require('tailwindcss'));
|
||||
postcssOptions.plugins.push(require('autoprefixer'));
|
||||
return postcssOptions;
|
||||
},
|
||||
};
|
||||
},
|
||||
require.resolve('docusaurus-lunr-search'),
|
||||
],
|
||||
presets: [
|
||||
[
|
||||
"docusaurus-preset-openapi",
|
||||
'docusaurus-preset-openapi',
|
||||
/** @type {import('docusaurus-preset-openapi').Options} */
|
||||
({
|
||||
docs: {
|
||||
showLastUpdateAuthor: true,
|
||||
showLastUpdateTime: true,
|
||||
|
||||
sidebarPath: require.resolve("./sidebars.js"),
|
||||
sidebarPath: require.resolve('./sidebars.js'),
|
||||
// Please change this to your repo.
|
||||
// Remove this to remove the "edit this page" links.
|
||||
editUrl: "https://github.com/immich-app/immich/tree/main/docs/",
|
||||
editUrl: 'https://github.com/immich-app/immich/tree/main/docs/',
|
||||
},
|
||||
api: {
|
||||
path: "../server/immich-openapi-specs.json",
|
||||
routeBasePath: "/docs/api",
|
||||
path: '../server/immich-openapi-specs.json',
|
||||
routeBasePath: '/docs/api',
|
||||
},
|
||||
// blog: {
|
||||
// showReadingTime: true,
|
||||
// editUrl: "https://github.com/immich-app/immich/tree/main/docs/",
|
||||
// },
|
||||
theme: {
|
||||
customCss: require.resolve("./src/css/custom.css"),
|
||||
customCss: require.resolve('./src/css/custom.css'),
|
||||
},
|
||||
}),
|
||||
],
|
||||
@@ -74,13 +75,13 @@ const config = {
|
||||
/** @type {import('@docusaurus/preset-classic').ThemeConfig} */
|
||||
({
|
||||
colorMode: {
|
||||
defaultMode: "dark",
|
||||
defaultMode: 'dark',
|
||||
},
|
||||
announcementBar: {
|
||||
id: "site_announcement_immich",
|
||||
id: 'site_announcement_immich',
|
||||
content: `⚠️ The project is under <strong>very active</strong> development. Expect bugs and changes. Do not use it as <strong>the only way</strong> to store your photos and videos!`,
|
||||
backgroundColor: "#593f00",
|
||||
textColor: "#ffefc9",
|
||||
backgroundColor: '#593f00',
|
||||
textColor: '#ffefc9',
|
||||
isCloseable: false,
|
||||
},
|
||||
docs: {
|
||||
@@ -90,72 +91,72 @@ const config = {
|
||||
},
|
||||
navbar: {
|
||||
logo: {
|
||||
alt: "Immich University Logo",
|
||||
src: "img/color-logo.png",
|
||||
srcDark: "img/logo.png",
|
||||
alt: 'Immich University Logo',
|
||||
src: 'img/color-logo.png',
|
||||
srcDark: 'img/logo.png',
|
||||
},
|
||||
items: [
|
||||
{
|
||||
to: "/docs/overview/introduction",
|
||||
position: "right",
|
||||
label: "Docs",
|
||||
to: '/docs/overview/introduction',
|
||||
position: 'right',
|
||||
label: 'Docs',
|
||||
},
|
||||
{
|
||||
to: "/docs/api",
|
||||
position: "right",
|
||||
label: "API",
|
||||
to: '/docs/api',
|
||||
position: 'right',
|
||||
label: 'API',
|
||||
},
|
||||
{
|
||||
href: "https://github.com/immich-app/immich",
|
||||
label: "GitHub",
|
||||
position: "right",
|
||||
href: 'https://github.com/immich-app/immich',
|
||||
label: 'GitHub',
|
||||
position: 'right',
|
||||
},
|
||||
{
|
||||
href: "https://github.com/orgs/immich-app/projects/1",
|
||||
label: "Roadmap",
|
||||
position: "right",
|
||||
href: 'https://github.com/orgs/immich-app/projects/1',
|
||||
label: 'Roadmap',
|
||||
position: 'right',
|
||||
},
|
||||
],
|
||||
},
|
||||
footer: {
|
||||
style: "light",
|
||||
style: 'light',
|
||||
links: [
|
||||
{
|
||||
title: "Overview",
|
||||
title: 'Overview',
|
||||
items: [
|
||||
{
|
||||
label: "Welcome",
|
||||
to: "/docs/overview/introduction",
|
||||
label: 'Welcome',
|
||||
to: '/docs/overview/introduction',
|
||||
},
|
||||
{
|
||||
label: "Installation",
|
||||
to: "/docs/install/requirements",
|
||||
label: 'Installation',
|
||||
to: '/docs/install/requirements',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Community",
|
||||
title: 'Community',
|
||||
items: [
|
||||
{
|
||||
label: "Discord",
|
||||
href: "https://discord.com/invite/D8JsnBEuKb",
|
||||
label: 'Discord',
|
||||
href: 'https://discord.com/invite/D8JsnBEuKb',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Links",
|
||||
title: 'Links',
|
||||
items: [
|
||||
// {
|
||||
// label: "Blog",
|
||||
// to: "/blog",
|
||||
// },
|
||||
{
|
||||
label: "GitHub",
|
||||
href: "https://github.com/immich-app/immich",
|
||||
label: 'GitHub',
|
||||
href: 'https://github.com/immich-app/immich',
|
||||
},
|
||||
{
|
||||
label: "Roadmap",
|
||||
href: "https://github.com/orgs/immich-app/projects/1",
|
||||
label: 'Roadmap',
|
||||
href: 'https://github.com/orgs/immich-app/projects/1',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -166,7 +167,7 @@ const config = {
|
||||
theme: lightCodeTheme,
|
||||
darkTheme: darkCodeTheme,
|
||||
},
|
||||
image: "overview/img/feature-panel.png",
|
||||
image: 'overview/img/feature-panel.png',
|
||||
}),
|
||||
};
|
||||
|
||||
|
||||
591
docs/package-lock.json
generated
@@ -13,6 +13,7 @@
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
"autoprefixer": "^10.4.13",
|
||||
"clsx": "^1.2.1",
|
||||
"docusaurus-lunr-search": "^2.3.2",
|
||||
"docusaurus-preset-openapi": "^0.6.3",
|
||||
"postcss": "^8.4.20",
|
||||
"prism-react-renderer": "^1.3.5",
|
||||
@@ -3634,6 +3635,11 @@
|
||||
"resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
|
||||
"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ=="
|
||||
},
|
||||
"node_modules/abbrev": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
|
||||
},
|
||||
"node_modules/accepts": {
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
|
||||
@@ -3903,6 +3909,11 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/aproba": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz",
|
||||
"integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ=="
|
||||
},
|
||||
"node_modules/arg": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
|
||||
@@ -3957,6 +3968,14 @@
|
||||
"node": ">= 4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/autocomplete.js": {
|
||||
"version": "0.37.1",
|
||||
"resolved": "https://registry.npmjs.org/autocomplete.js/-/autocomplete.js-0.37.1.tgz",
|
||||
"integrity": "sha512-PgSe9fHYhZEsm/9jggbjtVsGXJkPLvd+9mC7gZJ662vVL5CRWEtm/mIrrzCx0MrNxHVwxD5d00UOn6NsmL2LUQ==",
|
||||
"dependencies": {
|
||||
"immediate": "^3.2.3"
|
||||
}
|
||||
},
|
||||
"node_modules/autoprefixer": {
|
||||
"version": "10.4.13",
|
||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz",
|
||||
@@ -4148,6 +4167,15 @@
|
||||
"resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
|
||||
"integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw=="
|
||||
},
|
||||
"node_modules/bcp-47-match": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/bcp-47-match/-/bcp-47-match-1.0.3.tgz",
|
||||
"integrity": "sha512-LggQ4YTdjWQSKELZF5JwchnBa1u0pIQSZf5lSdOHEdbVP55h0qICA/FUp3+W99q0xqxYa1ZQizTUH87gecII5w==",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/big.js": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
|
||||
@@ -4583,6 +4611,11 @@
|
||||
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.5.0.tgz",
|
||||
"integrity": "sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw=="
|
||||
},
|
||||
"node_modules/classnames": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz",
|
||||
"integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw=="
|
||||
},
|
||||
"node_modules/clean-css": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.1.tgz",
|
||||
@@ -4743,6 +4776,14 @@
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"node_modules/color-support": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
|
||||
"integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
|
||||
"bin": {
|
||||
"color-support": "bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/colord": {
|
||||
"version": "2.9.3",
|
||||
"resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz",
|
||||
@@ -4887,6 +4928,11 @@
|
||||
"resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz",
|
||||
"integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw=="
|
||||
},
|
||||
"node_modules/console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
|
||||
"integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ=="
|
||||
},
|
||||
"node_modules/content-disposition": {
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz",
|
||||
@@ -5278,6 +5324,11 @@
|
||||
"url": "https://github.com/sponsors/fb55"
|
||||
}
|
||||
},
|
||||
"node_modules/css-selector-parser": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/css-selector-parser/-/css-selector-parser-1.4.1.tgz",
|
||||
"integrity": "sha512-HYPSb7y/Z7BNDCOrakL4raGO2zltZkbeXyAd6Tg9obzix6QhzxCotdBl6VT0Dv4vZfJGVz3WL/xaEI9Ly3ul0g=="
|
||||
},
|
||||
"node_modules/css-tree": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
|
||||
@@ -5664,6 +5715,18 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/direction": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/direction/-/direction-1.0.4.tgz",
|
||||
"integrity": "sha512-GYqKi1aH7PJXxdhTeZBFrg8vUBeKXi+cNprXsC1kpJcbcVnV9wBsrOu1cQEdG0WeQwlfHiy3XvnKfIrJ2R0NzQ==",
|
||||
"bin": {
|
||||
"direction": "cli.js"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/dlv": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
|
||||
@@ -5685,6 +5748,53 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/docusaurus-lunr-search": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/docusaurus-lunr-search/-/docusaurus-lunr-search-2.3.2.tgz",
|
||||
"integrity": "sha512-Ngvm2kXwliWThqAThXI1912rOKHlFL7BjIc+OVNUfzkjpk5ar4TFEh+EUaaMOLw4V0BBko3CW0Ym7prqqm3jLQ==",
|
||||
"dependencies": {
|
||||
"autocomplete.js": "^0.37.0",
|
||||
"classnames": "^2.2.6",
|
||||
"gauge": "^3.0.0",
|
||||
"hast-util-select": "^4.0.0",
|
||||
"hast-util-to-text": "^2.0.0",
|
||||
"hogan.js": "^3.0.2",
|
||||
"lunr": "^2.3.8",
|
||||
"lunr-languages": "^1.4.0",
|
||||
"minimatch": "^3.0.4",
|
||||
"object-assign": "^4.1.1",
|
||||
"rehype-parse": "^7.0.1",
|
||||
"to-vfile": "^6.1.0",
|
||||
"unified": "^9.0.0",
|
||||
"unist-util-is": "^4.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.10.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@docusaurus/core": "^2.0.0-alpha.60 || ^2.0.0",
|
||||
"react": "^16.8.4 || ^17",
|
||||
"react-dom": "^16.8.4 || ^17"
|
||||
}
|
||||
},
|
||||
"node_modules/docusaurus-lunr-search/node_modules/parse5": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
|
||||
"integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw=="
|
||||
},
|
||||
"node_modules/docusaurus-lunr-search/node_modules/rehype-parse": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-7.0.1.tgz",
|
||||
"integrity": "sha512-fOiR9a9xH+Le19i4fGzIEowAbwG7idy2Jzs4mOrFWBSJ0sNUgy0ev871dwWnbOo371SjgjG4pwzrbgSVrKxecw==",
|
||||
"dependencies": {
|
||||
"hast-util-from-parse5": "^6.0.0",
|
||||
"parse5": "^6.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/docusaurus-plugin-openapi": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/docusaurus-plugin-openapi/-/docusaurus-plugin-openapi-0.6.3.tgz",
|
||||
@@ -6689,6 +6799,43 @@
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
|
||||
},
|
||||
"node_modules/gauge": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz",
|
||||
"integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==",
|
||||
"dependencies": {
|
||||
"aproba": "^1.0.3 || ^2.0.0",
|
||||
"color-support": "^1.1.2",
|
||||
"console-control-strings": "^1.0.0",
|
||||
"has-unicode": "^2.0.1",
|
||||
"object-assign": "^4.1.1",
|
||||
"signal-exit": "^3.0.0",
|
||||
"string-width": "^4.2.3",
|
||||
"strip-ansi": "^6.0.1",
|
||||
"wide-align": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/gauge/node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||
},
|
||||
"node_modules/gauge/node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/gensync": {
|
||||
"version": "1.0.0-beta.2",
|
||||
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
||||
@@ -6994,6 +7141,11 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-unicode": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
|
||||
"integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ=="
|
||||
},
|
||||
"node_modules/has-yarn": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz",
|
||||
@@ -7037,6 +7189,24 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-has-property": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-has-property/-/hast-util-has-property-1.0.4.tgz",
|
||||
"integrity": "sha512-ghHup2voGfgFoHMGnaLHOjbYFACKrRh9KFttdCzMCbFoBMJXiNi2+XTrPP8+q6cDJM/RSqlCfVWrjp1H201rZg==",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-is-element": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-1.1.0.tgz",
|
||||
"integrity": "sha512-oUmNua0bFbdrD/ELDSSEadRVtWZOf3iF6Lbv81naqsIV99RnSCieTbWuWCY8BAeEfKJTKl0gRdokv+dELutHGQ==",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-parse-selector": {
|
||||
"version": "2.2.5",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz",
|
||||
@@ -7072,6 +7242,31 @@
|
||||
"resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
|
||||
"integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw=="
|
||||
},
|
||||
"node_modules/hast-util-select": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-select/-/hast-util-select-4.0.2.tgz",
|
||||
"integrity": "sha512-8EEG2//bN5rrzboPWD2HdS3ugLijNioS1pqOTIolXNf67xxShYw4SQEmVXd3imiBG+U2bC2nVTySr/iRAA7Cjg==",
|
||||
"dependencies": {
|
||||
"bcp-47-match": "^1.0.0",
|
||||
"comma-separated-tokens": "^1.0.0",
|
||||
"css-selector-parser": "^1.0.0",
|
||||
"direction": "^1.0.0",
|
||||
"hast-util-has-property": "^1.0.0",
|
||||
"hast-util-is-element": "^1.0.0",
|
||||
"hast-util-to-string": "^1.0.0",
|
||||
"hast-util-whitespace": "^1.0.0",
|
||||
"not": "^0.1.0",
|
||||
"nth-check": "^2.0.0",
|
||||
"property-information": "^5.0.0",
|
||||
"space-separated-tokens": "^1.0.0",
|
||||
"unist-util-visit": "^2.0.0",
|
||||
"zwitch": "^1.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-to-parse5": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-6.0.0.tgz",
|
||||
@@ -7088,6 +7283,38 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-to-string": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-1.0.4.tgz",
|
||||
"integrity": "sha512-eK0MxRX47AV2eZ+Lyr18DCpQgodvaS3fAQO2+b9Two9F5HEoRPhiUMNzoXArMJfZi2yieFzUBMRl3HNJ3Jus3w==",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-to-text": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-2.0.1.tgz",
|
||||
"integrity": "sha512-8nsgCARfs6VkwH2jJU9b8LNTuR4700na+0h3PqCaEk4MAnMDeu5P0tP8mjk9LLNGxIeQRLbiDbZVw6rku+pYsQ==",
|
||||
"dependencies": {
|
||||
"hast-util-is-element": "^1.0.0",
|
||||
"repeat-string": "^1.0.0",
|
||||
"unist-util-find-after": "^3.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-whitespace": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-1.0.4.tgz",
|
||||
"integrity": "sha512-I5GTdSfhYfAPNztx2xJRQpG8cuDSNt599/7YUn7Gx/WxNMsG+a835k97TDkFgk123cwjfwINaZknkKkphx/f2A==",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hastscript": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz",
|
||||
@@ -7133,6 +7360,18 @@
|
||||
"value-equal": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/hogan.js": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hogan.js/-/hogan.js-3.0.2.tgz",
|
||||
"integrity": "sha512-RqGs4wavGYJWE07t35JQccByczmNUXQT0E12ZYV1VKYu5UiAU9lsos/yBAcf840+zrUQQxgVduCR5/B8nNtibg==",
|
||||
"dependencies": {
|
||||
"mkdirp": "0.3.0",
|
||||
"nopt": "1.0.10"
|
||||
},
|
||||
"bin": {
|
||||
"hulk": "bin/hulk"
|
||||
}
|
||||
},
|
||||
"node_modules/hoist-non-react-statics": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
|
||||
@@ -7435,6 +7674,11 @@
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/immediate": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz",
|
||||
"integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q=="
|
||||
},
|
||||
"node_modules/immer": {
|
||||
"version": "9.0.16",
|
||||
"resolved": "https://registry.npmjs.org/immer/-/immer-9.0.16.tgz",
|
||||
@@ -8232,6 +8476,16 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/lunr": {
|
||||
"version": "2.3.9",
|
||||
"resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz",
|
||||
"integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow=="
|
||||
},
|
||||
"node_modules/lunr-languages": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/lunr-languages/-/lunr-languages-1.10.0.tgz",
|
||||
"integrity": "sha512-BBjKKcwrieJlzwwc9M5H/MRXGJ2qyOSDx/NXYiwkuKjiLOOoouh0WsDzeqcLoUWcX31y7i8sb8IgsZKObdUCkw=="
|
||||
},
|
||||
"node_modules/make-dir": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
|
||||
@@ -8538,6 +8792,15 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/mkdirp": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz",
|
||||
"integrity": "sha512-OHsdUcVAQ6pOtg5JYWpCBo9W/GySVuwvP9hueRMW7UqshC0tbfzLv8wjySTPm3tfUZ/21CE9E1pJagOA91Pxew==",
|
||||
"deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/monaco-editor": {
|
||||
"version": "0.31.1",
|
||||
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.31.1.tgz",
|
||||
@@ -8657,6 +8920,20 @@
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz",
|
||||
"integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg=="
|
||||
},
|
||||
"node_modules/nopt": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
|
||||
"integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==",
|
||||
"dependencies": {
|
||||
"abbrev": "1"
|
||||
},
|
||||
"bin": {
|
||||
"nopt": "bin/nopt.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/normalize-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||
@@ -8684,6 +8961,11 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/not": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/not/-/not-0.1.0.tgz",
|
||||
"integrity": "sha512-5PDmaAsVfnWUgTUbJ3ERwn7u79Z0dYxN9ErxCpVJJqe2RK0PJ3z+iFUxuqjwtlDDegXvtWoxD/3Fzxox7tFGWA=="
|
||||
},
|
||||
"node_modules/npm-run-path": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
|
||||
@@ -12774,6 +13056,19 @@
|
||||
"node": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/to-vfile": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/to-vfile/-/to-vfile-6.1.0.tgz",
|
||||
"integrity": "sha512-BxX8EkCxOAZe+D/ToHdDsJcVI4HqQfmw0tCkp31zf3dNP/XWIAjU4CmeuSwsSoOzOTqHPOL0KUzyZqJplkD0Qw==",
|
||||
"dependencies": {
|
||||
"is-buffer": "^2.0.0",
|
||||
"vfile": "^4.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/toidentifier": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
||||
@@ -12989,6 +13284,18 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/unist-util-find-after": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-3.0.0.tgz",
|
||||
"integrity": "sha512-ojlBqfsBftYXExNu3+hHLfJQ/X1jYY/9vdm4yZWjIbf0VuWF6CRufci1ZyoD/wV2TYMKxXUoNuoqwy+CkgzAiQ==",
|
||||
"dependencies": {
|
||||
"unist-util-is": "^4.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/unist-util-generated": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-1.1.6.tgz",
|
||||
@@ -13943,6 +14250,32 @@
|
||||
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
|
||||
"integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q=="
|
||||
},
|
||||
"node_modules/wide-align": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz",
|
||||
"integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==",
|
||||
"dependencies": {
|
||||
"string-width": "^1.0.2 || 2 || 3 || 4"
|
||||
}
|
||||
},
|
||||
"node_modules/wide-align/node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||
},
|
||||
"node_modules/wide-align/node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/widest-line": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz",
|
||||
@@ -16831,6 +17164,11 @@
|
||||
"resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
|
||||
"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ=="
|
||||
},
|
||||
"abbrev": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
|
||||
},
|
||||
"accepts": {
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
|
||||
@@ -17031,6 +17369,11 @@
|
||||
"picomatch": "^2.0.4"
|
||||
}
|
||||
},
|
||||
"aproba": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz",
|
||||
"integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ=="
|
||||
},
|
||||
"arg": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
|
||||
@@ -17076,6 +17419,14 @@
|
||||
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
|
||||
"integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg=="
|
||||
},
|
||||
"autocomplete.js": {
|
||||
"version": "0.37.1",
|
||||
"resolved": "https://registry.npmjs.org/autocomplete.js/-/autocomplete.js-0.37.1.tgz",
|
||||
"integrity": "sha512-PgSe9fHYhZEsm/9jggbjtVsGXJkPLvd+9mC7gZJ662vVL5CRWEtm/mIrrzCx0MrNxHVwxD5d00UOn6NsmL2LUQ==",
|
||||
"requires": {
|
||||
"immediate": "^3.2.3"
|
||||
}
|
||||
},
|
||||
"autoprefixer": {
|
||||
"version": "10.4.13",
|
||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz",
|
||||
@@ -17206,6 +17557,11 @@
|
||||
"resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
|
||||
"integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw=="
|
||||
},
|
||||
"bcp-47-match": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/bcp-47-match/-/bcp-47-match-1.0.3.tgz",
|
||||
"integrity": "sha512-LggQ4YTdjWQSKELZF5JwchnBa1u0pIQSZf5lSdOHEdbVP55h0qICA/FUp3+W99q0xqxYa1ZQizTUH87gecII5w=="
|
||||
},
|
||||
"big.js": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
|
||||
@@ -17502,6 +17858,11 @@
|
||||
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.5.0.tgz",
|
||||
"integrity": "sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw=="
|
||||
},
|
||||
"classnames": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz",
|
||||
"integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw=="
|
||||
},
|
||||
"clean-css": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.1.tgz",
|
||||
@@ -17624,6 +17985,11 @@
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"color-support": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
|
||||
"integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg=="
|
||||
},
|
||||
"colord": {
|
||||
"version": "2.9.3",
|
||||
"resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz",
|
||||
@@ -17744,6 +18110,11 @@
|
||||
"resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz",
|
||||
"integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw=="
|
||||
},
|
||||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
|
||||
"integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ=="
|
||||
},
|
||||
"content-disposition": {
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz",
|
||||
@@ -18000,6 +18371,11 @@
|
||||
"nth-check": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"css-selector-parser": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/css-selector-parser/-/css-selector-parser-1.4.1.tgz",
|
||||
"integrity": "sha512-HYPSb7y/Z7BNDCOrakL4raGO2zltZkbeXyAd6Tg9obzix6QhzxCotdBl6VT0Dv4vZfJGVz3WL/xaEI9Ly3ul0g=="
|
||||
},
|
||||
"css-tree": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
|
||||
@@ -18268,6 +18644,11 @@
|
||||
"path-type": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"direction": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/direction/-/direction-1.0.4.tgz",
|
||||
"integrity": "sha512-GYqKi1aH7PJXxdhTeZBFrg8vUBeKXi+cNprXsC1kpJcbcVnV9wBsrOu1cQEdG0WeQwlfHiy3XvnKfIrJ2R0NzQ=="
|
||||
},
|
||||
"dlv": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
|
||||
@@ -18286,6 +18667,43 @@
|
||||
"@leichtgewicht/ip-codec": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"docusaurus-lunr-search": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/docusaurus-lunr-search/-/docusaurus-lunr-search-2.3.2.tgz",
|
||||
"integrity": "sha512-Ngvm2kXwliWThqAThXI1912rOKHlFL7BjIc+OVNUfzkjpk5ar4TFEh+EUaaMOLw4V0BBko3CW0Ym7prqqm3jLQ==",
|
||||
"requires": {
|
||||
"autocomplete.js": "^0.37.0",
|
||||
"classnames": "^2.2.6",
|
||||
"gauge": "^3.0.0",
|
||||
"hast-util-select": "^4.0.0",
|
||||
"hast-util-to-text": "^2.0.0",
|
||||
"hogan.js": "^3.0.2",
|
||||
"lunr": "^2.3.8",
|
||||
"lunr-languages": "^1.4.0",
|
||||
"minimatch": "^3.0.4",
|
||||
"object-assign": "^4.1.1",
|
||||
"rehype-parse": "^7.0.1",
|
||||
"to-vfile": "^6.1.0",
|
||||
"unified": "^9.0.0",
|
||||
"unist-util-is": "^4.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"parse5": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
|
||||
"integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw=="
|
||||
},
|
||||
"rehype-parse": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-7.0.1.tgz",
|
||||
"integrity": "sha512-fOiR9a9xH+Le19i4fGzIEowAbwG7idy2Jzs4mOrFWBSJ0sNUgy0ev871dwWnbOo371SjgjG4pwzrbgSVrKxecw==",
|
||||
"requires": {
|
||||
"hast-util-from-parse5": "^6.0.0",
|
||||
"parse5": "^6.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"docusaurus-plugin-openapi": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/docusaurus-plugin-openapi/-/docusaurus-plugin-openapi-0.6.3.tgz",
|
||||
@@ -19036,6 +19454,39 @@
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
|
||||
},
|
||||
"gauge": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz",
|
||||
"integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==",
|
||||
"requires": {
|
||||
"aproba": "^1.0.3 || ^2.0.0",
|
||||
"color-support": "^1.1.2",
|
||||
"console-control-strings": "^1.0.0",
|
||||
"has-unicode": "^2.0.1",
|
||||
"object-assign": "^4.1.1",
|
||||
"signal-exit": "^3.0.0",
|
||||
"string-width": "^4.2.3",
|
||||
"strip-ansi": "^6.0.1",
|
||||
"wide-align": "^1.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||
},
|
||||
"string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"requires": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"gensync": {
|
||||
"version": "1.0.0-beta.2",
|
||||
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
||||
@@ -19266,6 +19717,11 @@
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
|
||||
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
|
||||
},
|
||||
"has-unicode": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
|
||||
"integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ=="
|
||||
},
|
||||
"has-yarn": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz",
|
||||
@@ -19298,6 +19754,16 @@
|
||||
"web-namespaces": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"hast-util-has-property": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-has-property/-/hast-util-has-property-1.0.4.tgz",
|
||||
"integrity": "sha512-ghHup2voGfgFoHMGnaLHOjbYFACKrRh9KFttdCzMCbFoBMJXiNi2+XTrPP8+q6cDJM/RSqlCfVWrjp1H201rZg=="
|
||||
},
|
||||
"hast-util-is-element": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-1.1.0.tgz",
|
||||
"integrity": "sha512-oUmNua0bFbdrD/ELDSSEadRVtWZOf3iF6Lbv81naqsIV99RnSCieTbWuWCY8BAeEfKJTKl0gRdokv+dELutHGQ=="
|
||||
},
|
||||
"hast-util-parse-selector": {
|
||||
"version": "2.2.5",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz",
|
||||
@@ -19327,6 +19793,27 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"hast-util-select": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-select/-/hast-util-select-4.0.2.tgz",
|
||||
"integrity": "sha512-8EEG2//bN5rrzboPWD2HdS3ugLijNioS1pqOTIolXNf67xxShYw4SQEmVXd3imiBG+U2bC2nVTySr/iRAA7Cjg==",
|
||||
"requires": {
|
||||
"bcp-47-match": "^1.0.0",
|
||||
"comma-separated-tokens": "^1.0.0",
|
||||
"css-selector-parser": "^1.0.0",
|
||||
"direction": "^1.0.0",
|
||||
"hast-util-has-property": "^1.0.0",
|
||||
"hast-util-is-element": "^1.0.0",
|
||||
"hast-util-to-string": "^1.0.0",
|
||||
"hast-util-whitespace": "^1.0.0",
|
||||
"not": "^0.1.0",
|
||||
"nth-check": "^2.0.0",
|
||||
"property-information": "^5.0.0",
|
||||
"space-separated-tokens": "^1.0.0",
|
||||
"unist-util-visit": "^2.0.0",
|
||||
"zwitch": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"hast-util-to-parse5": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-6.0.0.tgz",
|
||||
@@ -19339,6 +19826,26 @@
|
||||
"zwitch": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"hast-util-to-string": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-1.0.4.tgz",
|
||||
"integrity": "sha512-eK0MxRX47AV2eZ+Lyr18DCpQgodvaS3fAQO2+b9Two9F5HEoRPhiUMNzoXArMJfZi2yieFzUBMRl3HNJ3Jus3w=="
|
||||
},
|
||||
"hast-util-to-text": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-2.0.1.tgz",
|
||||
"integrity": "sha512-8nsgCARfs6VkwH2jJU9b8LNTuR4700na+0h3PqCaEk4MAnMDeu5P0tP8mjk9LLNGxIeQRLbiDbZVw6rku+pYsQ==",
|
||||
"requires": {
|
||||
"hast-util-is-element": "^1.0.0",
|
||||
"repeat-string": "^1.0.0",
|
||||
"unist-util-find-after": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"hast-util-whitespace": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-1.0.4.tgz",
|
||||
"integrity": "sha512-I5GTdSfhYfAPNztx2xJRQpG8cuDSNt599/7YUn7Gx/WxNMsG+a835k97TDkFgk123cwjfwINaZknkKkphx/f2A=="
|
||||
},
|
||||
"hastscript": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz",
|
||||
@@ -19374,6 +19881,15 @@
|
||||
"value-equal": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"hogan.js": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hogan.js/-/hogan.js-3.0.2.tgz",
|
||||
"integrity": "sha512-RqGs4wavGYJWE07t35JQccByczmNUXQT0E12ZYV1VKYu5UiAU9lsos/yBAcf840+zrUQQxgVduCR5/B8nNtibg==",
|
||||
"requires": {
|
||||
"mkdirp": "0.3.0",
|
||||
"nopt": "1.0.10"
|
||||
}
|
||||
},
|
||||
"hoist-non-react-statics": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
|
||||
@@ -19589,6 +20105,11 @@
|
||||
"queue": "6.0.2"
|
||||
}
|
||||
},
|
||||
"immediate": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz",
|
||||
"integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q=="
|
||||
},
|
||||
"immer": {
|
||||
"version": "9.0.16",
|
||||
"resolved": "https://registry.npmjs.org/immer/-/immer-9.0.16.tgz",
|
||||
@@ -20162,6 +20683,16 @@
|
||||
"yallist": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"lunr": {
|
||||
"version": "2.3.9",
|
||||
"resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz",
|
||||
"integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow=="
|
||||
},
|
||||
"lunr-languages": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/lunr-languages/-/lunr-languages-1.10.0.tgz",
|
||||
"integrity": "sha512-BBjKKcwrieJlzwwc9M5H/MRXGJ2qyOSDx/NXYiwkuKjiLOOoouh0WsDzeqcLoUWcX31y7i8sb8IgsZKObdUCkw=="
|
||||
},
|
||||
"make-dir": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
|
||||
@@ -20374,6 +20905,11 @@
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz",
|
||||
"integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g=="
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz",
|
||||
"integrity": "sha512-OHsdUcVAQ6pOtg5JYWpCBo9W/GySVuwvP9hueRMW7UqshC0tbfzLv8wjySTPm3tfUZ/21CE9E1pJagOA91Pxew=="
|
||||
},
|
||||
"monaco-editor": {
|
||||
"version": "0.31.1",
|
||||
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.31.1.tgz",
|
||||
@@ -20461,6 +20997,14 @@
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz",
|
||||
"integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg=="
|
||||
},
|
||||
"nopt": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
|
||||
"integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==",
|
||||
"requires": {
|
||||
"abbrev": "1"
|
||||
}
|
||||
},
|
||||
"normalize-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||
@@ -20476,6 +21020,11 @@
|
||||
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz",
|
||||
"integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A=="
|
||||
},
|
||||
"not": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/not/-/not-0.1.0.tgz",
|
||||
"integrity": "sha512-5PDmaAsVfnWUgTUbJ3ERwn7u79Z0dYxN9ErxCpVJJqe2RK0PJ3z+iFUxuqjwtlDDegXvtWoxD/3Fzxox7tFGWA=="
|
||||
},
|
||||
"npm-run-path": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
|
||||
@@ -23447,6 +23996,15 @@
|
||||
"is-number": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"to-vfile": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/to-vfile/-/to-vfile-6.1.0.tgz",
|
||||
"integrity": "sha512-BxX8EkCxOAZe+D/ToHdDsJcVI4HqQfmw0tCkp31zf3dNP/XWIAjU4CmeuSwsSoOzOTqHPOL0KUzyZqJplkD0Qw==",
|
||||
"requires": {
|
||||
"is-buffer": "^2.0.0",
|
||||
"vfile": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"toidentifier": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
||||
@@ -23588,6 +24146,14 @@
|
||||
"resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-2.0.3.tgz",
|
||||
"integrity": "sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw=="
|
||||
},
|
||||
"unist-util-find-after": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-3.0.0.tgz",
|
||||
"integrity": "sha512-ojlBqfsBftYXExNu3+hHLfJQ/X1jYY/9vdm4yZWjIbf0VuWF6CRufci1ZyoD/wV2TYMKxXUoNuoqwy+CkgzAiQ==",
|
||||
"requires": {
|
||||
"unist-util-is": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"unist-util-generated": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-1.1.6.tgz",
|
||||
@@ -24241,6 +24807,31 @@
|
||||
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
|
||||
"integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q=="
|
||||
},
|
||||
"wide-align": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz",
|
||||
"integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==",
|
||||
"requires": {
|
||||
"string-width": "^1.0.2 || 2 || 3 || 4"
|
||||
},
|
||||
"dependencies": {
|
||||
"emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||
},
|
||||
"string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"requires": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"widest-line": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz",
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
"autoprefixer": "^10.4.13",
|
||||
"clsx": "^1.2.1",
|
||||
"docusaurus-lunr-search": "^2.3.2",
|
||||
"docusaurus-preset-openapi": "^0.6.3",
|
||||
"postcss": "^8.4.20",
|
||||
"prism-react-renderer": "^1.3.5",
|
||||
|
||||
297
docs/src/theme/SearchBar/DocSearch.js
Normal file
@@ -0,0 +1,297 @@
|
||||
import Hogan from "hogan.js";
|
||||
import LunrSearchAdapter from "./lunar-search";
|
||||
import autocomplete from "autocomplete.js";
|
||||
import templates from "./templates";
|
||||
import utils from "./utils";
|
||||
import $ from "autocomplete.js/zepto";
|
||||
|
||||
class DocSearch {
|
||||
constructor({
|
||||
searchDocs,
|
||||
searchIndex,
|
||||
inputSelector,
|
||||
debug = false,
|
||||
baseUrl = '/',
|
||||
queryDataCallback = null,
|
||||
autocompleteOptions = {
|
||||
debug: false,
|
||||
hint: false,
|
||||
autoselect: true
|
||||
},
|
||||
transformData = false,
|
||||
queryHook = false,
|
||||
handleSelected = false,
|
||||
enhancedSearchInput = false,
|
||||
layout = "collumns"
|
||||
}) {
|
||||
this.input = DocSearch.getInputFromSelector(inputSelector);
|
||||
this.queryDataCallback = queryDataCallback || null;
|
||||
const autocompleteOptionsDebug =
|
||||
autocompleteOptions && autocompleteOptions.debug
|
||||
? autocompleteOptions.debug
|
||||
: false;
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
autocompleteOptions.debug = debug || autocompleteOptionsDebug;
|
||||
this.autocompleteOptions = autocompleteOptions;
|
||||
this.autocompleteOptions.cssClasses =
|
||||
this.autocompleteOptions.cssClasses || {};
|
||||
this.autocompleteOptions.cssClasses.prefix =
|
||||
this.autocompleteOptions.cssClasses.prefix || "ds";
|
||||
const inputAriaLabel =
|
||||
this.input &&
|
||||
typeof this.input.attr === "function" &&
|
||||
this.input.attr("aria-label");
|
||||
this.autocompleteOptions.ariaLabel =
|
||||
this.autocompleteOptions.ariaLabel || inputAriaLabel || "search input";
|
||||
|
||||
this.isSimpleLayout = layout === "simple";
|
||||
|
||||
this.client = new LunrSearchAdapter(searchDocs, searchIndex, baseUrl);
|
||||
|
||||
if (enhancedSearchInput) {
|
||||
this.input = DocSearch.injectSearchBox(this.input);
|
||||
}
|
||||
this.autocomplete = autocomplete(this.input, autocompleteOptions, [
|
||||
{
|
||||
source: this.getAutocompleteSource(transformData, queryHook),
|
||||
templates: {
|
||||
suggestion: DocSearch.getSuggestionTemplate(this.isSimpleLayout),
|
||||
footer: templates.footer,
|
||||
empty: DocSearch.getEmptyTemplate()
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
const customHandleSelected = handleSelected;
|
||||
this.handleSelected = customHandleSelected || this.handleSelected;
|
||||
|
||||
// We prevent default link clicking if a custom handleSelected is defined
|
||||
if (customHandleSelected) {
|
||||
$(".algolia-autocomplete").on("click", ".ds-suggestions a", event => {
|
||||
event.preventDefault();
|
||||
});
|
||||
}
|
||||
|
||||
this.autocomplete.on(
|
||||
"autocomplete:selected",
|
||||
this.handleSelected.bind(null, this.autocomplete.autocomplete)
|
||||
);
|
||||
|
||||
this.autocomplete.on(
|
||||
"autocomplete:shown",
|
||||
this.handleShown.bind(null, this.input)
|
||||
);
|
||||
|
||||
if (enhancedSearchInput) {
|
||||
DocSearch.bindSearchBoxEvent();
|
||||
}
|
||||
}
|
||||
|
||||
static injectSearchBox(input) {
|
||||
input.before(templates.searchBox);
|
||||
const newInput = input
|
||||
.prev()
|
||||
.prev()
|
||||
.find("input");
|
||||
input.remove();
|
||||
return newInput;
|
||||
}
|
||||
|
||||
static bindSearchBoxEvent() {
|
||||
$('.searchbox [type="reset"]').on("click", function () {
|
||||
$("input#docsearch").focus();
|
||||
$(this).addClass("hide");
|
||||
autocomplete.autocomplete.setVal("");
|
||||
});
|
||||
|
||||
$("input#docsearch").on("keyup", () => {
|
||||
const searchbox = document.querySelector("input#docsearch");
|
||||
const reset = document.querySelector('.searchbox [type="reset"]');
|
||||
reset.className = "searchbox__reset";
|
||||
if (searchbox.value.length === 0) {
|
||||
reset.className += " hide";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the matching input from a CSS selector, null if none matches
|
||||
* @function getInputFromSelector
|
||||
* @param {string} selector CSS selector that matches the search
|
||||
* input of the page
|
||||
* @returns {void}
|
||||
*/
|
||||
static getInputFromSelector(selector) {
|
||||
const input = $(selector).filter("input");
|
||||
return input.length ? $(input[0]) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the `source` method to be passed to autocomplete.js. It will query
|
||||
* the Algolia index and call the callbacks with the formatted hits.
|
||||
* @function getAutocompleteSource
|
||||
* @param {function} transformData An optional function to transform the hits
|
||||
* @param {function} queryHook An optional function to transform the query
|
||||
* @returns {function} Method to be passed as the `source` option of
|
||||
* autocomplete
|
||||
*/
|
||||
getAutocompleteSource(transformData, queryHook) {
|
||||
return (query, callback) => {
|
||||
if (queryHook) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
query = queryHook(query) || query;
|
||||
}
|
||||
this.client.search(query).then(hits => {
|
||||
if (
|
||||
this.queryDataCallback &&
|
||||
typeof this.queryDataCallback == "function"
|
||||
) {
|
||||
this.queryDataCallback(hits);
|
||||
}
|
||||
if (transformData) {
|
||||
hits = transformData(hits) || hits;
|
||||
}
|
||||
callback(DocSearch.formatHits(hits));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// Given a list of hits returned by the API, will reformat them to be used in
|
||||
// a Hogan template
|
||||
static formatHits(receivedHits) {
|
||||
const clonedHits = utils.deepClone(receivedHits);
|
||||
const hits = clonedHits.map(hit => {
|
||||
if (hit._highlightResult) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
hit._highlightResult = utils.mergeKeyWithParent(
|
||||
hit._highlightResult,
|
||||
"hierarchy"
|
||||
);
|
||||
}
|
||||
return utils.mergeKeyWithParent(hit, "hierarchy");
|
||||
});
|
||||
|
||||
// Group hits by category / subcategory
|
||||
let groupedHits = utils.groupBy(hits, "lvl0");
|
||||
$.each(groupedHits, (level, collection) => {
|
||||
const groupedHitsByLvl1 = utils.groupBy(collection, "lvl1");
|
||||
const flattenedHits = utils.flattenAndFlagFirst(
|
||||
groupedHitsByLvl1,
|
||||
"isSubCategoryHeader"
|
||||
);
|
||||
groupedHits[level] = flattenedHits;
|
||||
});
|
||||
groupedHits = utils.flattenAndFlagFirst(groupedHits, "isCategoryHeader");
|
||||
|
||||
// Translate hits into smaller objects to be send to the template
|
||||
return groupedHits.map(hit => {
|
||||
const url = DocSearch.formatURL(hit);
|
||||
const category = utils.getHighlightedValue(hit, "lvl0");
|
||||
const subcategory = utils.getHighlightedValue(hit, "lvl1") || category;
|
||||
const displayTitle = utils
|
||||
.compact([
|
||||
utils.getHighlightedValue(hit, "lvl2") || subcategory,
|
||||
utils.getHighlightedValue(hit, "lvl3"),
|
||||
utils.getHighlightedValue(hit, "lvl4"),
|
||||
utils.getHighlightedValue(hit, "lvl5"),
|
||||
utils.getHighlightedValue(hit, "lvl6")
|
||||
])
|
||||
.join(
|
||||
'<span class="aa-suggestion-title-separator" aria-hidden="true"> › </span>'
|
||||
);
|
||||
const text = utils.getSnippetedValue(hit, "content");
|
||||
const isTextOrSubcategoryNonEmpty =
|
||||
(subcategory && subcategory !== "") ||
|
||||
(displayTitle && displayTitle !== "");
|
||||
const isLvl1EmptyOrDuplicate =
|
||||
!subcategory || subcategory === "" || subcategory === category;
|
||||
const isLvl2 =
|
||||
displayTitle && displayTitle !== "" && displayTitle !== subcategory;
|
||||
const isLvl1 =
|
||||
!isLvl2 &&
|
||||
(subcategory && subcategory !== "" && subcategory !== category);
|
||||
const isLvl0 = !isLvl1 && !isLvl2;
|
||||
|
||||
return {
|
||||
isLvl0,
|
||||
isLvl1,
|
||||
isLvl2,
|
||||
isLvl1EmptyOrDuplicate,
|
||||
isCategoryHeader: hit.isCategoryHeader,
|
||||
isSubCategoryHeader: hit.isSubCategoryHeader,
|
||||
isTextOrSubcategoryNonEmpty,
|
||||
category,
|
||||
subcategory,
|
||||
title: displayTitle,
|
||||
text,
|
||||
url
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
static formatURL(hit) {
|
||||
const { url, anchor } = hit;
|
||||
if (url) {
|
||||
const containsAnchor = url.indexOf("#") !== -1;
|
||||
if (containsAnchor) return url;
|
||||
else if (anchor) return `${hit.url}#${hit.anchor}`;
|
||||
return url;
|
||||
} else if (anchor) return `#${hit.anchor}`;
|
||||
/* eslint-disable */
|
||||
console.warn("no anchor nor url for : ", JSON.stringify(hit));
|
||||
/* eslint-enable */
|
||||
return null;
|
||||
}
|
||||
|
||||
static getEmptyTemplate() {
|
||||
return args => Hogan.compile(templates.empty).render(args);
|
||||
}
|
||||
|
||||
static getSuggestionTemplate(isSimpleLayout) {
|
||||
const stringTemplate = isSimpleLayout
|
||||
? templates.suggestionSimple
|
||||
: templates.suggestion;
|
||||
const template = Hogan.compile(stringTemplate);
|
||||
return suggestion => template.render(suggestion);
|
||||
}
|
||||
|
||||
handleSelected(input, event, suggestion, datasetNumber, context = {}) {
|
||||
// Do nothing if click on the suggestion, as it's already a <a href>, the
|
||||
// browser will take care of it. This allow Ctrl-Clicking on results and not
|
||||
// having the main window being redirected as well
|
||||
if (context.selectionMethod === "click") {
|
||||
return;
|
||||
}
|
||||
|
||||
input.setVal("");
|
||||
window.location.assign(suggestion.url);
|
||||
}
|
||||
|
||||
handleShown(input) {
|
||||
const middleOfInput = input.offset().left + input.width() / 2;
|
||||
let middleOfWindow = $(document).width() / 2;
|
||||
|
||||
if (isNaN(middleOfWindow)) {
|
||||
middleOfWindow = 900;
|
||||
}
|
||||
|
||||
const alignClass =
|
||||
middleOfInput - middleOfWindow >= 0
|
||||
? "algolia-autocomplete-right"
|
||||
: "algolia-autocomplete-left";
|
||||
const otherAlignClass =
|
||||
middleOfInput - middleOfWindow < 0
|
||||
? "algolia-autocomplete-right"
|
||||
: "algolia-autocomplete-left";
|
||||
const autocompleteWrapper = $(".algolia-autocomplete");
|
||||
if (!autocompleteWrapper.hasClass(alignClass)) {
|
||||
autocompleteWrapper.addClass(alignClass);
|
||||
}
|
||||
|
||||
if (autocompleteWrapper.hasClass(otherAlignClass)) {
|
||||
autocompleteWrapper.removeClass(otherAlignClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default DocSearch;
|
||||
526
docs/src/theme/SearchBar/algolia.css
Normal file
114
docs/src/theme/SearchBar/index.js
Normal file
@@ -0,0 +1,114 @@
|
||||
import React, { useRef, useCallback, useState } from "react";
|
||||
import classnames from "classnames";
|
||||
import { useHistory } from "@docusaurus/router";
|
||||
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
|
||||
import { usePluginData } from '@docusaurus/useGlobalData';
|
||||
import useIsBrowser from "@docusaurus/useIsBrowser";
|
||||
const Search = props => {
|
||||
const initialized = useRef(false);
|
||||
const searchBarRef = useRef(null);
|
||||
const [indexReady, setIndexReady] = useState(false);
|
||||
const history = useHistory();
|
||||
const { siteConfig = {} } = useDocusaurusContext();
|
||||
const isBrowser = useIsBrowser();
|
||||
const { baseUrl } = siteConfig;
|
||||
const initAlgolia = (searchDocs, searchIndex, DocSearch) => {
|
||||
new DocSearch({
|
||||
searchDocs,
|
||||
searchIndex,
|
||||
baseUrl,
|
||||
inputSelector: "#search_input_react",
|
||||
// Override algolia's default selection event, allowing us to do client-side
|
||||
// navigation and avoiding a full page refresh.
|
||||
handleSelected: (_input, _event, suggestion) => {
|
||||
const url = suggestion.url || "/";
|
||||
// Use an anchor tag to parse the absolute url into a relative url
|
||||
// Alternatively, we can use new URL(suggestion.url) but its not supported in IE
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
// Algolia use closest parent element id #__docusaurus when a h1 page title does not have an id
|
||||
// So, we can safely remove it. See https://github.com/facebook/docusaurus/issues/1828 for more details.
|
||||
|
||||
history.push(url);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const pluginData = usePluginData('docusaurus-lunr-search');
|
||||
const getSearchDoc = () =>
|
||||
process.env.NODE_ENV === "production"
|
||||
? fetch(`${baseUrl}${pluginData.fileNames.searchDoc}`).then((content) => content.json())
|
||||
: Promise.resolve([]);
|
||||
|
||||
const getLunrIndex = () =>
|
||||
process.env.NODE_ENV === "production"
|
||||
? fetch(`${baseUrl}${pluginData.fileNames.lunrIndex}`).then((content) => content.json())
|
||||
: Promise.resolve([]);
|
||||
|
||||
const loadAlgolia = () => {
|
||||
if (!initialized.current) {
|
||||
Promise.all([
|
||||
getSearchDoc(),
|
||||
getLunrIndex(),
|
||||
import("./DocSearch"),
|
||||
import("./algolia.css")
|
||||
]).then(([searchDocs, searchIndex, { default: DocSearch }]) => {
|
||||
if (searchDocs.length === 0) {
|
||||
return;
|
||||
}
|
||||
initAlgolia(searchDocs, searchIndex, DocSearch);
|
||||
setIndexReady(true);
|
||||
});
|
||||
initialized.current = true;
|
||||
}
|
||||
};
|
||||
|
||||
const toggleSearchIconClick = useCallback(
|
||||
e => {
|
||||
if (!searchBarRef.current.contains(e.target)) {
|
||||
searchBarRef.current.focus();
|
||||
}
|
||||
|
||||
props.handleSearchBarToggle && props.handleSearchBarToggle(!props.isSearchBarExpanded);
|
||||
},
|
||||
[props.isSearchBarExpanded]
|
||||
);
|
||||
|
||||
if (isBrowser) {
|
||||
loadAlgolia();
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="navbar__search" key="search-box">
|
||||
<span
|
||||
aria-label="expand searchbar"
|
||||
role="button"
|
||||
className={classnames("search-icon", {
|
||||
"search-icon-hidden": props.isSearchBarExpanded
|
||||
})}
|
||||
onClick={toggleSearchIconClick}
|
||||
onKeyDown={toggleSearchIconClick}
|
||||
tabIndex={0}
|
||||
/>
|
||||
<input
|
||||
id="search_input_react"
|
||||
type="search"
|
||||
placeholder={indexReady ? 'Search' : 'Loading...'}
|
||||
aria-label="Search"
|
||||
className={classnames(
|
||||
"navbar__search-input",
|
||||
{ "search-bar-expanded": props.isSearchBarExpanded },
|
||||
{ "search-bar": !props.isSearchBarExpanded }
|
||||
)}
|
||||
onClick={loadAlgolia}
|
||||
onMouseOver={loadAlgolia}
|
||||
onFocus={toggleSearchIconClick}
|
||||
onBlur={toggleSearchIconClick}
|
||||
ref={searchBarRef}
|
||||
disabled={!indexReady}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Search;
|
||||
147
docs/src/theme/SearchBar/lunar-search.js
Normal file
@@ -0,0 +1,147 @@
|
||||
import lunr from "@generated/lunr.client";
|
||||
lunr.tokenizer.separator = /[\s\-/]+/;
|
||||
|
||||
class LunrSearchAdapter {
|
||||
constructor(searchDocs, searchIndex, baseUrl = '/') {
|
||||
this.searchDocs = searchDocs;
|
||||
this.lunrIndex = lunr.Index.load(searchIndex);
|
||||
this.baseUrl = baseUrl;
|
||||
}
|
||||
|
||||
getLunrResult(input) {
|
||||
return this.lunrIndex.query(function (query) {
|
||||
const tokens = lunr.tokenizer(input);
|
||||
query.term(tokens, {
|
||||
boost: 10
|
||||
});
|
||||
query.term(tokens, {
|
||||
wildcard: lunr.Query.wildcard.TRAILING
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getHit(doc, formattedTitle, formattedContent) {
|
||||
return {
|
||||
hierarchy: {
|
||||
lvl0: doc.pageTitle || doc.title,
|
||||
lvl1: doc.type === 0 ? null : doc.title
|
||||
},
|
||||
url: doc.url,
|
||||
_snippetResult: formattedContent ? {
|
||||
content: {
|
||||
value: formattedContent,
|
||||
matchLevel: "full"
|
||||
}
|
||||
} : null,
|
||||
_highlightResult: {
|
||||
hierarchy: {
|
||||
lvl0: {
|
||||
value: doc.type === 0 ? formattedTitle || doc.title : doc.pageTitle,
|
||||
},
|
||||
lvl1:
|
||||
doc.type === 0
|
||||
? null
|
||||
: {
|
||||
value: formattedTitle || doc.title
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
getTitleHit(doc, position, length) {
|
||||
const start = position[0];
|
||||
const end = position[0] + length;
|
||||
let formattedTitle = doc.title.substring(0, start) + '<span class="algolia-docsearch-suggestion--highlight">' + doc.title.substring(start, end) + '</span>' + doc.title.substring(end, doc.title.length);
|
||||
return this.getHit(doc, formattedTitle)
|
||||
}
|
||||
|
||||
getKeywordHit(doc, position, length) {
|
||||
const start = position[0];
|
||||
const end = position[0] + length;
|
||||
let formattedTitle = doc.title + '<br /><i>Keywords: ' + doc.keywords.substring(0, start) + '<span class="algolia-docsearch-suggestion--highlight">' + doc.keywords.substring(start, end) + '</span>' + doc.keywords.substring(end, doc.keywords.length) + '</i>'
|
||||
return this.getHit(doc, formattedTitle)
|
||||
}
|
||||
|
||||
getContentHit(doc, position) {
|
||||
const start = position[0];
|
||||
const end = position[0] + position[1];
|
||||
let previewStart = start;
|
||||
let previewEnd = end;
|
||||
let ellipsesBefore = true;
|
||||
let ellipsesAfter = true;
|
||||
for (let k = 0; k < 3; k++) {
|
||||
const nextSpace = doc.content.lastIndexOf(' ', previewStart - 2);
|
||||
const nextDot = doc.content.lastIndexOf('.', previewStart - 2);
|
||||
if ((nextDot > 0) && (nextDot > nextSpace)) {
|
||||
previewStart = nextDot + 1;
|
||||
ellipsesBefore = false;
|
||||
break;
|
||||
}
|
||||
if (nextSpace < 0) {
|
||||
previewStart = 0;
|
||||
ellipsesBefore = false;
|
||||
break;
|
||||
}
|
||||
previewStart = nextSpace + 1;
|
||||
}
|
||||
for (let k = 0; k < 10; k++) {
|
||||
const nextSpace = doc.content.indexOf(' ', previewEnd + 1);
|
||||
const nextDot = doc.content.indexOf('.', previewEnd + 1);
|
||||
if ((nextDot > 0) && (nextDot < nextSpace)) {
|
||||
previewEnd = nextDot;
|
||||
ellipsesAfter = false;
|
||||
break;
|
||||
}
|
||||
if (nextSpace < 0) {
|
||||
previewEnd = doc.content.length;
|
||||
ellipsesAfter = false;
|
||||
break;
|
||||
}
|
||||
previewEnd = nextSpace;
|
||||
}
|
||||
let preview = doc.content.substring(previewStart, start);
|
||||
if (ellipsesBefore) {
|
||||
preview = '... ' + preview;
|
||||
}
|
||||
preview += '<span class="algolia-docsearch-suggestion--highlight">' + doc.content.substring(start, end) + '</span>';
|
||||
preview += doc.content.substring(end, previewEnd);
|
||||
if (ellipsesAfter) {
|
||||
preview += ' ...';
|
||||
}
|
||||
return this.getHit(doc, null, preview);
|
||||
|
||||
}
|
||||
search(input) {
|
||||
return new Promise((resolve, rej) => {
|
||||
const results = this.getLunrResult(input);
|
||||
const hits = [];
|
||||
results.length > 5 && (results.length = 5);
|
||||
this.titleHitsRes = []
|
||||
this.contentHitsRes = []
|
||||
results.forEach(result => {
|
||||
const doc = this.searchDocs[result.ref];
|
||||
const { metadata } = result.matchData;
|
||||
for (let i in metadata) {
|
||||
if (metadata[i].title) {
|
||||
if (!this.titleHitsRes.includes(result.ref)) {
|
||||
const position = metadata[i].title.position[0]
|
||||
hits.push(this.getTitleHit(doc, position, input.length));
|
||||
this.titleHitsRes.push(result.ref);
|
||||
}
|
||||
} else if (metadata[i].content) {
|
||||
const position = metadata[i].content.position[0]
|
||||
hits.push(this.getContentHit(doc, position))
|
||||
} else if (metadata[i].keywords) {
|
||||
const position = metadata[i].keywords.position[0]
|
||||
hits.push(this.getKeywordHit(doc, position, input.length));
|
||||
this.titleHitsRes.push(result.ref);
|
||||
}
|
||||
}
|
||||
});
|
||||
hits.length > 5 && (hits.length = 5);
|
||||
resolve(hits);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default LunrSearchAdapter;
|
||||
33
docs/src/theme/SearchBar/styles.css
Normal file
@@ -0,0 +1,33 @@
|
||||
.search-icon {
|
||||
background-image: var(--ifm-navbar-search-input-icon);
|
||||
height: auto;
|
||||
width: 24px;
|
||||
cursor: pointer;
|
||||
padding: 8px;
|
||||
line-height: 32px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.search-icon-hidden {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
@media (max-width: 360px) {
|
||||
.search-bar {
|
||||
width: 0 !important;
|
||||
background: none !important;
|
||||
padding: 0 !important;
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
.search-bar-expanded {
|
||||
width: 9rem !important;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
display: inline;
|
||||
vertical-align: sub;
|
||||
}
|
||||
}
|
||||
112
docs/src/theme/SearchBar/templates.js
Normal file
@@ -0,0 +1,112 @@
|
||||
const prefix = 'algolia-docsearch';
|
||||
const suggestionPrefix = `${prefix}-suggestion`;
|
||||
const footerPrefix = `${prefix}-footer`;
|
||||
|
||||
const templates = {
|
||||
suggestion: `
|
||||
<a class="${suggestionPrefix}
|
||||
{{#isCategoryHeader}}${suggestionPrefix}__main{{/isCategoryHeader}}
|
||||
{{#isSubCategoryHeader}}${suggestionPrefix}__secondary{{/isSubCategoryHeader}}
|
||||
"
|
||||
aria-label="Link to the result"
|
||||
href="{{{url}}}"
|
||||
>
|
||||
<div class="${suggestionPrefix}--category-header">
|
||||
<span class="${suggestionPrefix}--category-header-lvl0">{{{category}}}</span>
|
||||
</div>
|
||||
<div class="${suggestionPrefix}--wrapper">
|
||||
<div class="${suggestionPrefix}--subcategory-column">
|
||||
<span class="${suggestionPrefix}--subcategory-column-text">{{{subcategory}}}</span>
|
||||
</div>
|
||||
{{#isTextOrSubcategoryNonEmpty}}
|
||||
<div class="${suggestionPrefix}--content">
|
||||
<div class="${suggestionPrefix}--subcategory-inline">{{{subcategory}}}</div>
|
||||
<div class="${suggestionPrefix}--title">{{{title}}}</div>
|
||||
{{#text}}<div class="${suggestionPrefix}--text">{{{text}}}</div>{{/text}}
|
||||
</div>
|
||||
{{/isTextOrSubcategoryNonEmpty}}
|
||||
</div>
|
||||
</a>
|
||||
`,
|
||||
suggestionSimple: `
|
||||
<div class="${suggestionPrefix}
|
||||
{{#isCategoryHeader}}${suggestionPrefix}__main{{/isCategoryHeader}}
|
||||
{{#isSubCategoryHeader}}${suggestionPrefix}__secondary{{/isSubCategoryHeader}}
|
||||
suggestion-layout-simple
|
||||
">
|
||||
<div class="${suggestionPrefix}--category-header">
|
||||
{{^isLvl0}}
|
||||
<span class="${suggestionPrefix}--category-header-lvl0 ${suggestionPrefix}--category-header-item">{{{category}}}</span>
|
||||
{{^isLvl1}}
|
||||
{{^isLvl1EmptyOrDuplicate}}
|
||||
<span class="${suggestionPrefix}--category-header-lvl1 ${suggestionPrefix}--category-header-item">
|
||||
{{{subcategory}}}
|
||||
</span>
|
||||
{{/isLvl1EmptyOrDuplicate}}
|
||||
{{/isLvl1}}
|
||||
{{/isLvl0}}
|
||||
<div class="${suggestionPrefix}--title ${suggestionPrefix}--category-header-item">
|
||||
{{#isLvl2}}
|
||||
{{{title}}}
|
||||
{{/isLvl2}}
|
||||
{{#isLvl1}}
|
||||
{{{subcategory}}}
|
||||
{{/isLvl1}}
|
||||
{{#isLvl0}}
|
||||
{{{category}}}
|
||||
{{/isLvl0}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="${suggestionPrefix}--wrapper">
|
||||
{{#text}}
|
||||
<div class="${suggestionPrefix}--content">
|
||||
<div class="${suggestionPrefix}--text">{{{text}}}</div>
|
||||
</div>
|
||||
{{/text}}
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
footer: `
|
||||
<div class="${footerPrefix}">
|
||||
</div>
|
||||
`,
|
||||
empty: `
|
||||
<div class="${suggestionPrefix}">
|
||||
<div class="${suggestionPrefix}--wrapper">
|
||||
<div class="${suggestionPrefix}--content ${suggestionPrefix}--no-results">
|
||||
<div class="${suggestionPrefix}--title">
|
||||
<div class="${suggestionPrefix}--text">
|
||||
No results found for query <b>"{{query}}"</b>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
searchBox: `
|
||||
<form novalidate="novalidate" onsubmit="return false;" class="searchbox">
|
||||
<div role="search" class="searchbox__wrapper">
|
||||
<input id="docsearch" type="search" name="search" placeholder="Search the docs" autocomplete="off" required="required" class="searchbox__input"/>
|
||||
<button type="submit" title="Submit your search query." class="searchbox__submit" >
|
||||
<svg width=12 height=12 role="img" aria-label="Search">
|
||||
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#sbx-icon-search-13"></use>
|
||||
</svg>
|
||||
</button>
|
||||
<button type="reset" title="Clear the search query." class="searchbox__reset hide">
|
||||
<svg width=12 height=12 role="img" aria-label="Reset">
|
||||
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#sbx-icon-clear-3"></use>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="svg-icons" style="height: 0; width: 0; position: absolute; visibility: hidden">
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<symbol id="sbx-icon-clear-3" viewBox="0 0 40 40"><path d="M16.228 20L1.886 5.657 0 3.772 3.772 0l1.885 1.886L20 16.228 34.343 1.886 36.228 0 40 3.772l-1.886 1.885L23.772 20l14.342 14.343L40 36.228 36.228 40l-1.885-1.886L20 23.772 5.657 38.114 3.772 40 0 36.228l1.886-1.885L16.228 20z" fill-rule="evenodd"></symbol>
|
||||
<symbol id="sbx-icon-search-13" viewBox="0 0 40 40"><path d="M26.806 29.012a16.312 16.312 0 0 1-10.427 3.746C7.332 32.758 0 25.425 0 16.378 0 7.334 7.333 0 16.38 0c9.045 0 16.378 7.333 16.378 16.38 0 3.96-1.406 7.593-3.746 10.426L39.547 37.34c.607.608.61 1.59-.004 2.203a1.56 1.56 0 0 1-2.202.004L26.807 29.012zm-10.427.627c7.322 0 13.26-5.938 13.26-13.26 0-7.324-5.938-13.26-13.26-13.26-7.324 0-13.26 5.936-13.26 13.26 0 7.322 5.936 13.26 13.26 13.26z" fill-rule="evenodd"></symbol>
|
||||
</svg>
|
||||
</div>
|
||||
`,
|
||||
};
|
||||
|
||||
export default templates;
|
||||
270
docs/src/theme/SearchBar/utils.js
Normal file
@@ -0,0 +1,270 @@
|
||||
import $ from "autocomplete.js/zepto";
|
||||
|
||||
const utils = {
|
||||
/*
|
||||
* Move the content of an object key one level higher.
|
||||
* eg.
|
||||
* {
|
||||
* name: 'My name',
|
||||
* hierarchy: {
|
||||
* lvl0: 'Foo',
|
||||
* lvl1: 'Bar'
|
||||
* }
|
||||
* }
|
||||
* Will be converted to
|
||||
* {
|
||||
* name: 'My name',
|
||||
* lvl0: 'Foo',
|
||||
* lvl1: 'Bar'
|
||||
* }
|
||||
* @param {Object} object Main object
|
||||
* @param {String} property Main object key to move up
|
||||
* @return {Object}
|
||||
* @throws Error when key is not an attribute of Object or is not an object itself
|
||||
*/
|
||||
mergeKeyWithParent(object, property) {
|
||||
if (object[property] === undefined) {
|
||||
return object;
|
||||
}
|
||||
if (typeof object[property] !== 'object') {
|
||||
return object;
|
||||
}
|
||||
const newObject = $.extend({}, object, object[property]);
|
||||
delete newObject[property];
|
||||
return newObject;
|
||||
},
|
||||
/*
|
||||
* Group all objects of a collection by the value of the specified attribute
|
||||
* If the attribute is a string, use the lowercase form.
|
||||
*
|
||||
* eg.
|
||||
* groupBy([
|
||||
* {name: 'Tim', category: 'dev'},
|
||||
* {name: 'Vincent', category: 'dev'},
|
||||
* {name: 'Ben', category: 'sales'},
|
||||
* {name: 'Jeremy', category: 'sales'},
|
||||
* {name: 'AlexS', category: 'dev'},
|
||||
* {name: 'AlexK', category: 'sales'}
|
||||
* ], 'category');
|
||||
* =>
|
||||
* {
|
||||
* 'devs': [
|
||||
* {name: 'Tim', category: 'dev'},
|
||||
* {name: 'Vincent', category: 'dev'},
|
||||
* {name: 'AlexS', category: 'dev'}
|
||||
* ],
|
||||
* 'sales': [
|
||||
* {name: 'Ben', category: 'sales'},
|
||||
* {name: 'Jeremy', category: 'sales'},
|
||||
* {name: 'AlexK', category: 'sales'}
|
||||
* ]
|
||||
* }
|
||||
* @param {array} collection Array of objects to group
|
||||
* @param {String} property The attribute on which apply the grouping
|
||||
* @return {array}
|
||||
* @throws Error when one of the element does not have the specified property
|
||||
*/
|
||||
groupBy(collection, property) {
|
||||
const newCollection = {};
|
||||
$.each(collection, (index, item) => {
|
||||
if (item[property] === undefined) {
|
||||
throw new Error(`[groupBy]: Object has no key ${property}`);
|
||||
}
|
||||
let key = item[property];
|
||||
if (typeof key === 'string') {
|
||||
key = key.toLowerCase();
|
||||
}
|
||||
// fix #171 the given data type of docsearch hits might be conflict with the properties of the native Object,
|
||||
// such as the constructor, so we need to do this check.
|
||||
if (!Object.prototype.hasOwnProperty.call(newCollection, key)) {
|
||||
newCollection[key] = [];
|
||||
}
|
||||
newCollection[key].push(item);
|
||||
});
|
||||
return newCollection;
|
||||
},
|
||||
/*
|
||||
* Return an array of all the values of the specified object
|
||||
* eg.
|
||||
* values({
|
||||
* foo: 42,
|
||||
* bar: true,
|
||||
* baz: 'yep'
|
||||
* })
|
||||
* =>
|
||||
* [42, true, yep]
|
||||
* @param {object} object Object to extract values from
|
||||
* @return {array}
|
||||
*/
|
||||
values(object) {
|
||||
return Object.keys(object).map(key => object[key]);
|
||||
},
|
||||
/*
|
||||
* Flattens an array
|
||||
* eg.
|
||||
* flatten([1, 2, [3, 4], [5, 6]])
|
||||
* =>
|
||||
* [1, 2, 3, 4, 5, 6]
|
||||
* @param {array} array Array to flatten
|
||||
* @return {array}
|
||||
*/
|
||||
flatten(array) {
|
||||
const results = [];
|
||||
array.forEach(value => {
|
||||
if (!Array.isArray(value)) {
|
||||
results.push(value);
|
||||
return;
|
||||
}
|
||||
value.forEach(subvalue => {
|
||||
results.push(subvalue);
|
||||
});
|
||||
});
|
||||
return results;
|
||||
},
|
||||
/*
|
||||
* Flatten all values of an object into an array, marking each first element of
|
||||
* each group with a specific flag
|
||||
* eg.
|
||||
* flattenAndFlagFirst({
|
||||
* 'devs': [
|
||||
* {name: 'Tim', category: 'dev'},
|
||||
* {name: 'Vincent', category: 'dev'},
|
||||
* {name: 'AlexS', category: 'dev'}
|
||||
* ],
|
||||
* 'sales': [
|
||||
* {name: 'Ben', category: 'sales'},
|
||||
* {name: 'Jeremy', category: 'sales'},
|
||||
* {name: 'AlexK', category: 'sales'}
|
||||
* ]
|
||||
* , 'isTop');
|
||||
* =>
|
||||
* [
|
||||
* {name: 'Tim', category: 'dev', isTop: true},
|
||||
* {name: 'Vincent', category: 'dev', isTop: false},
|
||||
* {name: 'AlexS', category: 'dev', isTop: false},
|
||||
* {name: 'Ben', category: 'sales', isTop: true},
|
||||
* {name: 'Jeremy', category: 'sales', isTop: false},
|
||||
* {name: 'AlexK', category: 'sales', isTop: false}
|
||||
* ]
|
||||
* @param {object} object Object to flatten
|
||||
* @param {string} flag Flag to set to true on first element of each group
|
||||
* @return {array}
|
||||
*/
|
||||
flattenAndFlagFirst(object, flag) {
|
||||
const values = this.values(object).map(collection =>
|
||||
collection.map((item, index) => {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
item[flag] = index === 0;
|
||||
return item;
|
||||
})
|
||||
);
|
||||
return this.flatten(values);
|
||||
},
|
||||
/*
|
||||
* Removes all empty strings, null, false and undefined elements array
|
||||
* eg.
|
||||
* compact([42, false, null, undefined, '', [], 'foo']);
|
||||
* =>
|
||||
* [42, [], 'foo']
|
||||
* @param {array} array Array to compact
|
||||
* @return {array}
|
||||
*/
|
||||
compact(array) {
|
||||
const results = [];
|
||||
array.forEach(value => {
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
results.push(value);
|
||||
});
|
||||
return results;
|
||||
},
|
||||
/*
|
||||
* Returns the highlighted value of the specified key in the specified object.
|
||||
* If no highlighted value is available, will return the key value directly
|
||||
* eg.
|
||||
* getHighlightedValue({
|
||||
* _highlightResult: {
|
||||
* text: {
|
||||
* value: '<mark>foo</mark>'
|
||||
* }
|
||||
* },
|
||||
* text: 'foo'
|
||||
* }, 'text');
|
||||
* =>
|
||||
* '<mark>foo</mark>'
|
||||
* @param {object} object Hit object returned by the Algolia API
|
||||
* @param {string} property Object key to look for
|
||||
* @return {string}
|
||||
**/
|
||||
getHighlightedValue(object, property) {
|
||||
if (
|
||||
object._highlightResult &&
|
||||
object._highlightResult.hierarchy_camel &&
|
||||
object._highlightResult.hierarchy_camel[property] &&
|
||||
object._highlightResult.hierarchy_camel[property].matchLevel &&
|
||||
object._highlightResult.hierarchy_camel[property].matchLevel !== 'none' &&
|
||||
object._highlightResult.hierarchy_camel[property].value
|
||||
) {
|
||||
return object._highlightResult.hierarchy_camel[property].value;
|
||||
}
|
||||
if (
|
||||
object._highlightResult &&
|
||||
object._highlightResult &&
|
||||
object._highlightResult[property] &&
|
||||
object._highlightResult[property].value
|
||||
) {
|
||||
return object._highlightResult[property].value;
|
||||
}
|
||||
return object[property];
|
||||
},
|
||||
/*
|
||||
* Returns the snippeted value of the specified key in the specified object.
|
||||
* If no highlighted value is available, will return the key value directly.
|
||||
* Will add starting and ending ellipsis (…) if we detect that a sentence is
|
||||
* incomplete
|
||||
* eg.
|
||||
* getSnippetedValue({
|
||||
* _snippetResult: {
|
||||
* text: {
|
||||
* value: '<mark>This is an unfinished sentence</mark>'
|
||||
* }
|
||||
* },
|
||||
* text: 'This is an unfinished sentence'
|
||||
* }, 'text');
|
||||
* =>
|
||||
* '<mark>This is an unfinished sentence</mark>…'
|
||||
* @param {object} object Hit object returned by the Algolia API
|
||||
* @param {string} property Object key to look for
|
||||
* @return {string}
|
||||
**/
|
||||
getSnippetedValue(object, property) {
|
||||
if (
|
||||
!object._snippetResult ||
|
||||
!object._snippetResult[property] ||
|
||||
!object._snippetResult[property].value
|
||||
) {
|
||||
return object[property];
|
||||
}
|
||||
let snippet = object._snippetResult[property].value;
|
||||
|
||||
if (snippet[0] !== snippet[0].toUpperCase()) {
|
||||
snippet = `…${snippet}`;
|
||||
}
|
||||
if (['.', '!', '?'].indexOf(snippet[snippet.length - 1]) === -1) {
|
||||
snippet = `${snippet}…`;
|
||||
}
|
||||
return snippet;
|
||||
},
|
||||
/*
|
||||
* Deep clone an object.
|
||||
* Note: This will not clone functions and dates
|
||||
* @param {object} object Object to clone
|
||||
* @return {object}
|
||||
*/
|
||||
deepClone(object) {
|
||||
return JSON.parse(JSON.stringify(object));
|
||||
},
|
||||
};
|
||||
|
||||
export default utils;
|
||||
15
install.sh
@@ -2,19 +2,10 @@ echo "Starting Immich installation..."
|
||||
|
||||
ip_address=$(hostname -I | awk '{print $1}')
|
||||
|
||||
release_version=$(curl --silent "https://api.github.com/repos/immich-app/immich/releases/latest" |
|
||||
grep '"tag_name":' |
|
||||
sed -E 's/.*"([^"]+)".*/\1/')
|
||||
RED='\033[0;31m'
|
||||
GREEN='\032[0;31m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
get_release_version() {
|
||||
curl --silent "https://api.github.com/repos/immich-app/immich/releases/latest" | # Get latest release from GitHub api
|
||||
grep '"tag_name":' | # Get tag line
|
||||
sed -E 's/.*"([^"]+)".*/\1/' # Pluck JSON value
|
||||
}
|
||||
|
||||
create_immich_directory() {
|
||||
echo "Creating Immich directory..."
|
||||
mkdir -p ./immich-app/immich-data
|
||||
@@ -23,12 +14,12 @@ create_immich_directory() {
|
||||
|
||||
download_docker_compose_file() {
|
||||
echo "Downloading docker-compose.yml..."
|
||||
curl -L https://raw.githubusercontent.com/immich-app/immich/$release_version/docker/docker-compose.yml -o ./docker-compose.yml >/dev/null 2>&1
|
||||
curl -L https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml -o ./docker-compose.yml >/dev/null 2>&1
|
||||
}
|
||||
|
||||
download_dot_env_file() {
|
||||
echo "Downloading .env file..."
|
||||
curl -L https://raw.githubusercontent.com/immich-app/immich/$release_version/docker/example.env -o ./.env >/dev/null 2>&1
|
||||
curl -L https://github.com/immich-app/immich/releases/latest/download/example.env -o ./.env >/dev/null 2>&1
|
||||
}
|
||||
|
||||
replace_env_value() {
|
||||
@@ -69,7 +60,7 @@ start_docker_compose() {
|
||||
show_friendly_message() {
|
||||
echo "Succesfully deployed Immich!"
|
||||
echo "You can access the website at http://$ip_address:2283 and the server URL for the mobile app is http://$ip_address:2283/api"
|
||||
echo "The backup (or upload) location is $upload_location"
|
||||
echo "The library location is $upload_location"
|
||||
echo "---------------------------------------------------"
|
||||
echo "If you want to configure custom information of the server, including the database, Redis information, or the backup (or upload) location, etc.
|
||||
|
||||
|
||||
@@ -34,3 +34,15 @@ download:
|
||||
locale_code: pt-BR
|
||||
- file: mobile/assets/i18n/pl-PL.json
|
||||
locale_code: pl-PL
|
||||
- file: mobile/assets/i18n/sv-SE.json
|
||||
locale_code: sv-SE
|
||||
- file: mobile/assets/i18n/sk-SK.json
|
||||
locale_code: sk-SK
|
||||
- file: mobile/assets/i18n/zh-CN.json
|
||||
locale_code: zh-CN
|
||||
- file: mobile/assets/i18n/ru-RU.json
|
||||
locale_code: ru-RU
|
||||
- file: mobile/assets/i18n/cs-CZ.json
|
||||
locale_code: cs-CZ
|
||||
- file: mobile/assets/i18n/nb-NO.json
|
||||
locale_code: nb-NO
|
||||
|
||||
@@ -1,4 +1 @@
|
||||
node_modules/
|
||||
upload/
|
||||
dist/
|
||||
|
||||
venv/
|
||||
@@ -1,24 +0,0 @@
|
||||
module.exports = {
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
project: 'tsconfig.json',
|
||||
sourceType: 'module',
|
||||
},
|
||||
plugins: ['@typescript-eslint/eslint-plugin'],
|
||||
extends: [
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:prettier/recommended',
|
||||
],
|
||||
root: true,
|
||||
env: {
|
||||
node: true,
|
||||
jest: true,
|
||||
},
|
||||
ignorePatterns: ['.eslintrc.js'],
|
||||
rules: {
|
||||
'@typescript-eslint/interface-name-prefix': 'off',
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
},
|
||||
};
|
||||
43
machine-learning/.gitignore
vendored
@@ -1,37 +1,6 @@
|
||||
# compiled output
|
||||
/dist
|
||||
/node_modules
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
pnpm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
|
||||
# Tests
|
||||
/coverage
|
||||
/.nyc_output
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# IDE - VSCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
|
||||
upload/
|
||||
*.zip
|
||||
*.onnx
|
||||
upload/
|
||||
venv/
|
||||
__pycache__/
|
||||
model-cache/
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all"
|
||||
}
|
||||
@@ -1,34 +1,27 @@
|
||||
FROM node:16-bullseye-slim as builder
|
||||
FROM python:3.10 as builder
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
PIP_NO_CACHE_DIR=true
|
||||
|
||||
RUN python -m venv /opt/venv
|
||||
RUN /opt/venv/bin/pip install --pre torch -f https://download.pytorch.org/whl/nightly/cpu/torch_nightly.html
|
||||
RUN /opt/venv/bin/pip install transformers tqdm numpy scikit-learn scipy nltk sentencepiece flask Pillow gunicorn
|
||||
RUN /opt/venv/bin/pip install --no-deps sentence-transformers
|
||||
|
||||
FROM python:3.10-slim
|
||||
|
||||
ENV NODE_ENV=production
|
||||
|
||||
COPY --from=builder /opt/venv /opt/venv
|
||||
|
||||
ENV TRANSFORMERS_CACHE=/cache \
|
||||
PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
PATH="/opt/venv/bin:$PATH"
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install gcc g++ make cmake python3 python3-pip -y
|
||||
|
||||
COPY package.json package-lock.json ./
|
||||
|
||||
RUN npm ci
|
||||
RUN npm rebuild @tensorflow/tfjs-node --build-from-source
|
||||
|
||||
COPY . .
|
||||
|
||||
FROM builder as prod
|
||||
|
||||
RUN npm run build
|
||||
RUN npm prune --omit=dev
|
||||
|
||||
FROM node:16-bullseye-slim
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY --from=prod /usr/src/app/node_modules ./node_modules
|
||||
COPY --from=prod /usr/src/app/dist ./dist
|
||||
|
||||
COPY package.json package-lock.json ./
|
||||
COPY entrypoint.sh ./
|
||||
|
||||
# CMD [ "node", "dist/main" ]
|
||||
CMD ["gunicorn", "src.main:server"]
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Hau Tran
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,4 +1,5 @@
|
||||
|
||||
# Microservices for Immich
|
||||
# Immich Machine Learning
|
||||
|
||||
## Image Classifier
|
||||
- Object Detection
|
||||
- Image Classification
|
||||
@@ -1,4 +0,0 @@
|
||||
#! /bin/sh
|
||||
# npm run typeorm migration:run
|
||||
# npm run start:prod
|
||||
exec node dist/main.js
|
||||
29
machine-learning/gunicorn.conf.py
Normal file
@@ -0,0 +1,29 @@
|
||||
"""
|
||||
Gunicorn configuration options.
|
||||
https://docs.gunicorn.org/en/stable/settings.html
|
||||
"""
|
||||
import os
|
||||
|
||||
|
||||
# Set the bind address based on the env
|
||||
port = os.getenv("MACHINE_LEARNING_PORT") or "3003"
|
||||
listen_ip = os.getenv("MACHINE_LEARNING_IP") or "0.0.0.0"
|
||||
bind = [f"{listen_ip}:{port}"]
|
||||
|
||||
# Preload the Flask app / models etc. before starting the server
|
||||
preload_app = True
|
||||
|
||||
# Logging settings - log to stdout and set log level
|
||||
accesslog = "-"
|
||||
loglevel = os.getenv("MACHINE_LEARNING_LOG_LEVEL") or "info"
|
||||
|
||||
# Worker settings
|
||||
# ----------------------
|
||||
# It is important these are chosen carefully as per
|
||||
# https://pythonspeed.com/articles/gunicorn-in-docker/
|
||||
# Otherwise we get workers failing to respond to heartbeat checks,
|
||||
# especially as requests take a long time to complete.
|
||||
workers = 2
|
||||
threads = 4
|
||||
worker_tmp_dir = "/dev/shm"
|
||||
timeout = 60
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"collection": "@nestjs/schematics",
|
||||
"sourceRoot": "src"
|
||||
}
|
||||
16346
machine-learning/package-lock.json
generated
@@ -1,71 +0,0 @@
|
||||
{
|
||||
"name": "nest_microservices",
|
||||
"version": "0.0.1",
|
||||
"description": "",
|
||||
"author": "",
|
||||
"private": true,
|
||||
"license": "UNLICENSED",
|
||||
"scripts": {
|
||||
"prebuild": "rimraf dist",
|
||||
"build": "nest build",
|
||||
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
||||
"start": "nest start",
|
||||
"start:dev": "nest start --watch",
|
||||
"start:debug": "nest start --debug --watch",
|
||||
"start:prod": "node dist/main",
|
||||
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"test:cov": "jest --coverage",
|
||||
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
|
||||
"test:e2e": "jest --config ./test/jest-e2e.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "^8.0.0",
|
||||
"@nestjs/core": "^8.0.0",
|
||||
"@tensorflow-models/coco-ssd": "^2.2.2",
|
||||
"@tensorflow-models/mobilenet": "^2.1.0",
|
||||
"@tensorflow/tfjs-node": "^3.19.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "^8.2.4",
|
||||
"@nestjs/schematics": "^8.0.0",
|
||||
"@nestjs/testing": "^8.0.0",
|
||||
"@types/express": "^4.17.13",
|
||||
"@types/jest": "27.4.1",
|
||||
"@types/node": "^16.0.0",
|
||||
"@types/supertest": "^2.0.11",
|
||||
"@typescript-eslint/eslint-plugin": "^5.0.0",
|
||||
"@typescript-eslint/parser": "^5.0.0",
|
||||
"eslint": "^8.0.1",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"jest": "^27.2.5",
|
||||
"prettier": "^2.3.2",
|
||||
"rimraf": "^3.0.2",
|
||||
"source-map-support": "^0.5.20",
|
||||
"supertest": "^6.1.3",
|
||||
"ts-jest": "^27.0.3",
|
||||
"ts-loader": "^9.2.3",
|
||||
"ts-node": "^10.0.0",
|
||||
"tsconfig-paths": "^3.10.1",
|
||||
"typescript": "^4.3.5"
|
||||
},
|
||||
"jest": {
|
||||
"moduleFileExtensions": [
|
||||
"js",
|
||||
"json",
|
||||
"ts"
|
||||
],
|
||||
"rootDir": "src",
|
||||
"testRegex": ".*\\.spec\\.ts$",
|
||||
"transform": {
|
||||
"^.+\\.(t|j)s$": "ts-jest"
|
||||
},
|
||||
"collectCoverageFrom": [
|
||||
"**/*.(t|j)s"
|
||||
],
|
||||
"coverageDirectory": "../coverage",
|
||||
"testEnvironment": "node"
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ImageClassifierModule } from './image-classifier/image-classifier.module';
|
||||
import { ObjectDetectionModule } from './object-detection/object-detection.module';
|
||||
|
||||
@Module({
|
||||
imports: [ImageClassifierModule, ObjectDetectionModule],
|
||||
controllers: [],
|
||||
providers: [],
|
||||
})
|
||||
export class AppModule {}
|
||||
@@ -1,14 +0,0 @@
|
||||
import { Body, Controller, Post } from '@nestjs/common';
|
||||
import { ImageClassifierService } from './image-classifier.service';
|
||||
|
||||
@Controller('image-classifier')
|
||||
export class ImageClassifierController {
|
||||
constructor(
|
||||
private readonly imageClassifierService: ImageClassifierService,
|
||||
) { }
|
||||
|
||||
@Post('/tag-image')
|
||||
async tagImage(@Body('thumbnailPath') thumbnailPath: string) {
|
||||
return await this.imageClassifierService.tagImage(thumbnailPath);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ImageClassifierService } from './image-classifier.service';
|
||||
import { ImageClassifierController } from './image-classifier.controller';
|
||||
|
||||
@Module({
|
||||
controllers: [ImageClassifierController],
|
||||
providers: [ImageClassifierService],
|
||||
})
|
||||
export class ImageClassifierModule {}
|
||||
@@ -1,49 +0,0 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import * as mobilenet from '@tensorflow-models/mobilenet';
|
||||
import * as cocoSsd from '@tensorflow-models/coco-ssd';
|
||||
import * as tf from '@tensorflow/tfjs-node';
|
||||
import * as fs from 'fs';
|
||||
|
||||
@Injectable()
|
||||
export class ImageClassifierService {
|
||||
private readonly MOBILENET_VERSION = 2;
|
||||
private readonly MOBILENET_ALPHA = 1.0;
|
||||
|
||||
private mobileNetModel: mobilenet.MobileNet;
|
||||
|
||||
constructor() {
|
||||
Logger.log(
|
||||
`Running Node TensorFlow Version : ${tf.version['tfjs']}`,
|
||||
'ImageClassifier',
|
||||
);
|
||||
mobilenet
|
||||
.load({
|
||||
version: this.MOBILENET_VERSION,
|
||||
alpha: this.MOBILENET_ALPHA,
|
||||
})
|
||||
.then((mobilenetModel) => (this.mobileNetModel = mobilenetModel));
|
||||
}
|
||||
|
||||
async tagImage(thumbnailPath: string) {
|
||||
try {
|
||||
const isExist = fs.existsSync(thumbnailPath);
|
||||
if (isExist) {
|
||||
const tags = [];
|
||||
const image = fs.readFileSync(thumbnailPath);
|
||||
const decodedImage = tf.node.decodeImage(image, 3) as tf.Tensor3D;
|
||||
const predictions = await this.mobileNetModel.classify(decodedImage);
|
||||
|
||||
for (const prediction of predictions) {
|
||||
if (prediction.probability >= 0.1) {
|
||||
tags.push(...prediction.className.split(',').map((e) => e.trim()));
|
||||
}
|
||||
}
|
||||
|
||||
tf.dispose(decodedImage);
|
||||
return tags;
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Error reading file ', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
73
machine-learning/src/main.py
Normal file
@@ -0,0 +1,73 @@
|
||||
import os
|
||||
from flask import Flask, request
|
||||
from transformers import pipeline
|
||||
from sentence_transformers import SentenceTransformer, util
|
||||
from PIL import Image
|
||||
|
||||
is_dev = os.getenv('NODE_ENV') == 'development'
|
||||
server_port = os.getenv('MACHINE_LEARNING_PORT', 3003)
|
||||
server_host = os.getenv('MACHINE_LEARNING_HOST', '0.0.0.0')
|
||||
|
||||
classification_model = os.getenv('MACHINE_LEARNING_CLASSIFICATION_MODEL', 'microsoft/resnet-50')
|
||||
object_model = os.getenv('MACHINE_LEARNING_OBJECT_MODEL', 'hustvl/yolos-tiny')
|
||||
clip_image_model = os.getenv('MACHINE_LEARNING_CLIP_IMAGE_MODEL', 'clip-ViT-B-32')
|
||||
clip_text_model = os.getenv('MACHINE_LEARNING_CLIP_TEXT_MODEL', 'clip-ViT-B-32')
|
||||
|
||||
_model_cache = {}
|
||||
def _get_model(model, task=None):
|
||||
global _model_cache
|
||||
key = '|'.join([model, str(task)])
|
||||
if key not in _model_cache:
|
||||
if task:
|
||||
_model_cache[key] = pipeline(model=model, task=task)
|
||||
else:
|
||||
_model_cache[key] = SentenceTransformer(model)
|
||||
return _model_cache[key]
|
||||
|
||||
server = Flask(__name__)
|
||||
|
||||
@server.route("/ping")
|
||||
def ping():
|
||||
return "pong"
|
||||
|
||||
@server.route("/object-detection/detect-object", methods=['POST'])
|
||||
def object_detection():
|
||||
model = _get_model(object_model, 'object-detection')
|
||||
assetPath = request.json['thumbnailPath']
|
||||
return run_engine(model, assetPath), 200
|
||||
|
||||
@server.route("/image-classifier/tag-image", methods=['POST'])
|
||||
def image_classification():
|
||||
model = _get_model(classification_model, 'image-classification')
|
||||
assetPath = request.json['thumbnailPath']
|
||||
return run_engine(model, assetPath), 200
|
||||
|
||||
@server.route("/sentence-transformer/encode-image", methods=['POST'])
|
||||
def clip_encode_image():
|
||||
model = _get_model(clip_image_model)
|
||||
assetPath = request.json['thumbnailPath']
|
||||
return model.encode(Image.open(assetPath)).tolist(), 200
|
||||
|
||||
@server.route("/sentence-transformer/encode-text", methods=['POST'])
|
||||
def clip_encode_text():
|
||||
model = _get_model(clip_text_model)
|
||||
text = request.json['text']
|
||||
return model.encode(text).tolist(), 200
|
||||
|
||||
def run_engine(engine, path):
|
||||
result = []
|
||||
predictions = engine(path)
|
||||
|
||||
for index, pred in enumerate(predictions):
|
||||
tags = pred['label'].split(', ')
|
||||
if (pred['score'] > 0.9):
|
||||
result = [*result, *tags]
|
||||
|
||||
if (len(result) > 1):
|
||||
result = list(set(result))
|
||||
|
||||
return result
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
server.run(debug=is_dev, host=server_host, port=server_port)
|
||||
@@ -1,27 +0,0 @@
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { AppModule } from './app.module';
|
||||
import { Logger } from '@nestjs/common';
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule);
|
||||
|
||||
const port = Number(process.env.MACHINE_LEARNING_PORT) || 3003;
|
||||
|
||||
await app.listen(port, () => {
|
||||
if (process.env.NODE_ENV == 'development') {
|
||||
Logger.log(
|
||||
'Running Immich Machine Learning in DEVELOPMENT environment',
|
||||
'IMMICH MICROSERVICES',
|
||||
);
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV == 'production') {
|
||||
Logger.log(
|
||||
'Running Immich Machine Learning in PRODUCTION environment',
|
||||
'IMMICH MICROSERVICES',
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bootstrap();
|
||||
@@ -1,15 +0,0 @@
|
||||
import { Body, Controller, Post } from '@nestjs/common';
|
||||
import { ObjectDetectionService } from './object-detection.service';
|
||||
import { Logger } from '@nestjs/common';
|
||||
|
||||
@Controller('object-detection')
|
||||
export class ObjectDetectionController {
|
||||
constructor(
|
||||
private readonly objectDetectionService: ObjectDetectionService,
|
||||
) { }
|
||||
|
||||
@Post('/detect-object')
|
||||
async detectObject(@Body('thumbnailPath') thumbnailPath: string) {
|
||||
return await this.objectDetectionService.detectObject(thumbnailPath);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ObjectDetectionService } from './object-detection.service';
|
||||
import { ObjectDetectionController } from './object-detection.controller';
|
||||
|
||||
@Module({
|
||||
controllers: [ObjectDetectionController],
|
||||
providers: [ObjectDetectionService],
|
||||
})
|
||||
export class ObjectDetectionModule {}
|
||||
@@ -1,39 +0,0 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import * as cocoSsd from '@tensorflow-models/coco-ssd';
|
||||
import * as tf from '@tensorflow/tfjs-node';
|
||||
import * as fs from 'fs';
|
||||
|
||||
@Injectable()
|
||||
export class ObjectDetectionService {
|
||||
private cocoSsdModel: cocoSsd.ObjectDetection;
|
||||
|
||||
constructor() {
|
||||
Logger.log(
|
||||
`Running Node TensorFlow Version : ${tf.version['tfjs']}`,
|
||||
'ObjectDetection',
|
||||
);
|
||||
cocoSsd.load().then((model) => (this.cocoSsdModel = model));
|
||||
}
|
||||
async detectObject(thumbnailPath: string) {
|
||||
try {
|
||||
const isExist = fs.existsSync(thumbnailPath);
|
||||
if (isExist) {
|
||||
const tags = new Set();
|
||||
const image = fs.readFileSync(thumbnailPath);
|
||||
const decodedImage = tf.node.decodeImage(image, 3) as tf.Tensor3D;
|
||||
const predictions = await this.cocoSsdModel.detect(decodedImage);
|
||||
|
||||
for (const result of predictions) {
|
||||
if (result.score > 0.5) {
|
||||
tags.add(result.class);
|
||||
}
|
||||
}
|
||||
|
||||
tf.dispose(decodedImage);
|
||||
return [...tags];
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Error reading file ', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"declaration": true,
|
||||
"removeComments": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"target": "es2017",
|
||||
"sourceMap": true,
|
||||
"outDir": "./dist",
|
||||
"baseUrl": "./",
|
||||
"incremental": true,
|
||||
"skipLibCheck": true,
|
||||
"strictNullChecks": false,
|
||||
"noImplicitAny": false,
|
||||
"strictBindCallApply": false,
|
||||
"forceConsistentCasingInFileNames": false,
|
||||
"noFallthroughCasesInSwitch": false
|
||||
}
|
||||
}
|
||||
@@ -60,22 +60,27 @@ else
|
||||
fi
|
||||
|
||||
if [ "$CURRENT_SERVER" != "$NEXT_SERVER" ]; then
|
||||
|
||||
echo "Pumping Server: $CURRENT_SERVER => $NEXT_SERVER"
|
||||
|
||||
sed -i "s/^ \"version\": \"$CURRENT_SERVER\",$/ \"version\": \"$NEXT_SERVER\",/" server/package.json
|
||||
sed -i "s/^ \"version\": \"$CURRENT_SERVER\",$/ \"version\": \"$NEXT_SERVER\",/" server/package-lock.json
|
||||
sed -i "s/\"version\": \"$CURRENT_SERVER\",$/\"version\": \"$NEXT_SERVER\",/" server/immich-openapi-specs.json
|
||||
sed -i "s/\"android\.injected\.version\.name\" => \"$CURRENT_SERVER\",/\"android\.injected\.version\.name\" => \"$NEXT_SERVER\",/" mobile/android/fastlane/Fastfile
|
||||
sed -i "s/version_number: \"$CURRENT_SERVER\"$/version_number: \"$NEXT_SERVER\"/" mobile/ios/fastlane/Fastfile
|
||||
fi
|
||||
|
||||
if [ "$CURRENT_MOBILE" != "$NEXT_MOBILE" ]; then
|
||||
|
||||
echo "Pumping Mobile: $CURRENT_MOBILE => $NEXT_MOBILE"
|
||||
|
||||
sed -i "s/\"android\.injected\.version\.code\" => $CURRENT_MOBILE,/\"android\.injected\.version\.code\" => $NEXT_MOBILE,/" mobile/android/fastlane/Fastfile
|
||||
sed -i "s/^version: $CURRENT_SERVER+$CURRENT_MOBILE$/version: $NEXT_SERVER+$NEXT_MOBILE/" mobile/pubspec.yaml
|
||||
fi
|
||||
|
||||
sed -i "s/^ \"version\": \"$CURRENT_SERVER\",$/ \"version\": \"$NEXT_SERVER\",/" server/package.json
|
||||
sed -i "s/^ \"version\": \"$CURRENT_SERVER\",$/ \"version\": \"$NEXT_SERVER\",/" server/package-lock.json
|
||||
sed -i "s/\"version\": \"$CURRENT_SERVER\",$/\"version\": \"$NEXT_SERVER\",/" server/immich-openapi-specs.json
|
||||
sed -i "s/\"android\.injected\.version\.name\" => \"$CURRENT_SERVER\",/\"android\.injected\.version\.name\" => \"$NEXT_SERVER\",/" mobile/android/fastlane/Fastfile
|
||||
sed -i "s/version_number: \"$CURRENT_SERVER\"$/version_number: \"$NEXT_SERVER\"/" mobile/ios/fastlane/Fastfile
|
||||
sed -i "s/\"android\.injected\.version\.code\" => $CURRENT_MOBILE,/\"android\.injected\.version\.code\" => $NEXT_MOBILE,/" mobile/android/fastlane/Fastfile
|
||||
sed -i "s/^version: $CURRENT_SERVER+$CURRENT_MOBILE$/version: $NEXT_SERVER+$NEXT_MOBILE/" mobile/pubspec.yaml
|
||||
|
||||
# OpenApi Generated Files
|
||||
sed -i "s/API version: $CURRENT_SERVER,$/API version: $NEXT_SERVER/" mobile/openapi/README.md
|
||||
sed -i "s/OpenAPI document: $CURRENT_SERVER,$/OpenAPI document: $NEXT_SERVER/" web/src/api/open-api/api.ts
|
||||
sed -i "s/OpenAPI document: $CURRENT_SERVER,$/OpenAPI document: $NEXT_SERVER/" web/src/api/open-api/base.ts
|
||||
sed -i "s/OpenAPI document: $CURRENT_SERVER,$/OpenAPI document: $NEXT_SERVER/" web/src/api/open-api/common.ts
|
||||
sed -i "s/OpenAPI document: $CURRENT_SERVER,$/OpenAPI document: $NEXT_SERVER/" web/src/api/open-api/configuration.ts
|
||||
sed -i "s/OpenAPI document: $CURRENT_SERVER,$/OpenAPI document: $NEXT_SERVER/" web/src/api/open-api/index.ts
|
||||
|
||||
echo "IMMICH_VERSION=v$NEXT_SERVER" >>$GITHUB_ENV
|
||||
|
||||
4
mobile/.fvm/fvm_config.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"flutterSdkVersion": "3.7.0",
|
||||
"flavors": {}
|
||||
}
|
||||
4
mobile/.gitignore
vendored
@@ -24,7 +24,6 @@
|
||||
|
||||
# Flutter/Dart/Pub related
|
||||
**/doc/api/
|
||||
**/ios/
|
||||
.dart_tool/
|
||||
.flutter-plugins
|
||||
.flutter-plugins-dependencies
|
||||
@@ -32,6 +31,7 @@
|
||||
.pub-cache/
|
||||
.pub/
|
||||
/build/
|
||||
.fvm/flutter_sdk
|
||||
|
||||
# Web related
|
||||
lib/generated_plugin_registrant.dart
|
||||
@@ -48,4 +48,4 @@ app.*.map.json
|
||||
/android/app/release
|
||||
|
||||
# Fastlane
|
||||
ios/fastlane/report.xml
|
||||
ios/fastlane/report.xml
|
||||
|
||||
1
mobile/.isar
Submodule
@@ -23,6 +23,7 @@ if (flutterVersionName == null) {
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||
|
||||
def keystoreProperties = new Properties()
|
||||
@@ -86,4 +87,6 @@ dependencies {
|
||||
implementation "androidx.work:work-runtime-ktx:$work_version"
|
||||
implementation "androidx.concurrent:concurrent-futures:$concurrent_version"
|
||||
implementation "com.google.guava:guava:$guava_version"
|
||||
implementation "com.github.bumptech.glide:glide:$glide_version"
|
||||
kapt "com.github.bumptech.glide:compiler:$glide_version"
|
||||
}
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
<application android:label="Immich" android:name=".ImmichApp" android:usesCleartextTraffic="true"
|
||||
android:icon="@mipmap/ic_launcher" android:requestLegacyExternalStorage="true">
|
||||
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.EnableImpeller"
|
||||
android:value="false" />
|
||||
|
||||
<activity android:name=".MainActivity" android:exported="true" android:launchMode="singleTop"
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
@@ -54,6 +59,7 @@
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
|
||||
<queries>
|
||||
<intent>
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package app.alextran.immich
|
||||
|
||||
import com.bumptech.glide.annotation.GlideModule
|
||||
import com.bumptech.glide.module.AppGlideModule
|
||||
|
||||
@GlideModule
|
||||
class AppGlideModule : AppGlideModule()
|
||||
@@ -1,15 +1,16 @@
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.6.10'
|
||||
ext.kotlin_version = '1.8.20'
|
||||
ext.work_version = '2.7.1'
|
||||
ext.concurrent_version = '1.1.0'
|
||||
ext.guava_version = '31.0.1-android'
|
||||
ext.glide_version = '4.14.2'
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.1.2'
|
||||
classpath 'com.android.tools.build:gradle:7.4.2'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,8 +35,8 @@ platform :android do
|
||||
task: 'bundle',
|
||||
build_type: 'Release',
|
||||
properties: {
|
||||
"android.injected.version.code" => 69,
|
||||
"android.injected.version.name" => "1.46.1",
|
||||
"android.injected.version.code" => 77,
|
||||
"android.injected.version.name" => "1.54.1",
|
||||
}
|
||||
)
|
||||
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')
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
* Adds over scroll at end of timeline to select images on the bottom
|
||||
* Fixes back navigation with tab controller
|
||||
* Shows a toast after adding to favorites
|
||||
* Fixed download button style
|
||||
* Cleaned up action bar, changed horizontal icon more to info icon
|
||||
* Responsive display of exif data in bottom sheet
|
||||
* Upgrade to Flutter 3.7
|
||||
* Fix freeze bug on app start
|
||||
* Uses profile photo for user avatar drawer
|
||||
* Spinning flower
|
||||
* Remove unsplash placeholder image and style empty places
|
||||
@@ -0,0 +1,6 @@
|
||||
* Scroll to top when tapping photos while already on photo page.
|
||||
* Delete goes to next page instead of popping back to the main timeline.
|
||||
* Improve date formatting.
|
||||
* Styling and linter.
|
||||
* User get logged out upon clicking on any thing after logging in.
|
||||
* Improve reliability of asset loading and indexing.
|
||||
@@ -0,0 +1,2 @@
|
||||
* Fix no album thumbnail lead to no album selection shown and add global logs
|
||||
* Fix remove asset from gallery view
|
||||
@@ -0,0 +1,4 @@
|
||||
* fix: Prevents duplicate taps navigating to the same route twice.
|
||||
* fix: Adds safe area to album to stop from clipping bottom of albums.
|
||||
* feat: Adds onboarding for permissions.
|
||||
* feat: Responsive list and grid view of backup album selection and fixes search filter.
|
||||
@@ -0,0 +1,12 @@
|
||||
* Enter server first for login
|
||||
* Sync assets, albums & users to local database on device
|
||||
* Fixes hero animation on main timeline by
|
||||
* Transparent bottom Android navigation bar
|
||||
* Fix do not crash on malformed asset duration
|
||||
* Gallery viewer fullscreen edge case
|
||||
* Fix Sorted shared album and added share user doesn't reflect change in album view
|
||||
* Allow app to be used offline
|
||||
* No longer wait for background backup in settings
|
||||
* Share album name and adaptive shared album display
|
||||
* Persist album sort order
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
* refactor: migrate all Hive boxes to Isar database.
|
||||
* feat: Use new search API and GridView for Places / Locations.
|
||||
* refactor: store backup settings on device.
|
||||
* feat: Explore favorites, recently added, videos, and motion photos.
|
||||
* fix: Fixed mobile app not reporting webm MIME type.
|
||||
* feature: Hardening synchronization mechanism + Pull to refresh.
|
||||
* feat: improve explore page and allow metadata search.
|
||||
* feat: Allow headers to upload large file in chunk.
|
||||
@@ -0,0 +1,3 @@
|
||||
* Improved logging page experience
|
||||
* Fixed shared page does not get all shared albums
|
||||
* Fixed hero animation re-enabling on immich asset grid
|
||||
@@ -0,0 +1,10 @@
|
||||
* Fixes white navigation bar in Android 8.
|
||||
* Add bottom safe area to video player controls.
|
||||
* Fix null check operator on null value.
|
||||
* Add troubleshooting toggle.
|
||||
* Configurable log level.
|
||||
* Consistent handling of DateTime in SyncService.
|
||||
* Fix asset removal edge cases.
|
||||
* Archive feature on mobile.
|
||||
* Add AssetState and proper asset updating.
|
||||
* Video player disposes early.
|
||||
@@ -5,17 +5,17 @@
|
||||
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000281">
|
||||
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000294">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="1: bundleRelease" time="142.850758">
|
||||
<testcase classname="fastlane.lanes" name="1: bundleRelease" time="75.683384">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="2: upload_to_play_store" time="39.589103">
|
||||
<testcase classname="fastlane.lanes" name="2: upload_to_play_store" time="24.839722">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#Fri Jun 23 08:50:38 CEST 2017
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip
|
||||
distributionSha256Sum=cd5c2958a107ee7f0722004a12d0f8559b4564c34daad7df06cffd4d12a426d0
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-all.zip
|
||||
distributionSha256Sum=518a863631feb7452b8f1b3dc2aaee5f388355cc3421bbd0275fbeadd77e84b2
|
||||
@@ -1,10 +1,14 @@
|
||||
{
|
||||
"add_to_album_bottom_sheet_added": "Přidáno do {album}",
|
||||
"add_to_album_bottom_sheet_already_exists": "Již v {album}",
|
||||
"album_info_card_backup_album_excluded": "VYLOUČENO",
|
||||
"album_info_card_backup_album_included": "ZAHRNUTO",
|
||||
"album_thumbnail_card_item": "1 položka",
|
||||
"album_thumbnail_card_items": "{} položky",
|
||||
"album_thumbnail_card_items": "{} položek",
|
||||
"album_thumbnail_card_shared": "Sdíleno",
|
||||
"album_viewer_appbar_share_delete": "odstranit album",
|
||||
"album_thumbnail_owned": "Vlastněno",
|
||||
"album_thumbnail_shared_by": "Sdílené od {}",
|
||||
"album_viewer_appbar_share_delete": "Odstranit album",
|
||||
"album_viewer_appbar_share_err_delete": "Nepodařilo se odstranit album",
|
||||
"album_viewer_appbar_share_err_leave": "Nepodařilo se ukončit album",
|
||||
"album_viewer_appbar_share_err_remove": "Při odstraňování souborů z alba se vyskytly problémy.",
|
||||
@@ -12,6 +16,11 @@
|
||||
"album_viewer_appbar_share_leave": "Opustit album",
|
||||
"album_viewer_appbar_share_remove": "Odstranit z alba",
|
||||
"album_viewer_page_share_add_users": "Přidat uživatele",
|
||||
"all_videos_page_title": "Videa",
|
||||
"asset_list_layout_settings_dynamic_layout_title": "Dynamické rozložení",
|
||||
"asset_list_layout_settings_group_by": "Seskupit položky podle",
|
||||
"asset_list_layout_settings_group_by_month": "Měsíc",
|
||||
"asset_list_layout_settings_group_by_month_day": "Měsíc + den",
|
||||
"asset_list_settings_subtitle": "Nastavení rozložení mřížky fotografií",
|
||||
"asset_list_settings_title": "Fotografická mřížka",
|
||||
"backup_album_selection_page_albums_device": "Alba v zařízení ({})",
|
||||
@@ -21,31 +30,34 @@
|
||||
"backup_album_selection_page_selection_info": "Informace o výběru",
|
||||
"backup_album_selection_page_total_assets": "Celkový počet jedinečných souborů",
|
||||
"backup_all": "Vše",
|
||||
"backup_background_service_backup_failed_message": "Zálohování zdrojů selhalo. Zkouším to znovu...",
|
||||
"backup_background_service_backup_failed_message": "Zálohování médií selhalo. Zkouším to znovu...",
|
||||
"backup_background_service_connection_failed_message": "Nepodařilo se připojit k serveru. Zkouším to znovu...",
|
||||
"backup_background_service_current_upload_notification": "Nahrávání {}",
|
||||
"backup_background_service_default_notification": "Kontrola nových zdrojů {}",
|
||||
"backup_background_service_default_notification": "Kontrola nových médií {}",
|
||||
"backup_background_service_error_title": "Chyba zálohování",
|
||||
"backup_background_service_in_progress_notification": "Vytvářím kopii vašich zdrojů...",
|
||||
"backup_background_service_in_progress_notification": "Vytvářím kopii vašich médií...",
|
||||
"backup_background_service_upload_failure_notification": "Nepodařilo se nahrát {}",
|
||||
"backup_controller_page_albums": "Zálohovaná alba",
|
||||
"backup_controller_page_background_app_refresh_disabled_content": "Povolte obnovení aplikace na pozadí v Nastavení > Obecné > Obnovení aplikace na pozadí, abyste mohli používat zálohování na pozadí.",
|
||||
"backup_controller_page_background_app_refresh_disabled_title": " Obnovování aplikací na pozadí je vypnuté",
|
||||
"backup_controller_page_background_app_refresh_enable_button_text": "Přejít do nastavení",
|
||||
"backup_controller_page_background_battery_info_link": "Ukaž mi jak",
|
||||
"backup_controller_page_background_battery_info_message": "Chcete-li dosáhnout nejlepších výsledků při zálohování na pozadí, vypněte všechny optimalizace baterie, které omezují aktivitu na pozadí pro Immich ve vašem zařízení. Jelikož to závisí na zařízení, zkontrolujte požadované informace pro výrobce vašeho zařízení.",
|
||||
"backup_controller_page_background_battery_info_message": "Chcete-li dosáhnout nejlepších výsledků při zálohování na pozadí, vypněte všechny optimalizace baterie, které omezují aktivitu na pozadí pro Immich ve vašem zařízení. \n\nJelikož je to závislé na typu zařízení, vyhledejte požadované informace pro výrobce vašeho zařízení.",
|
||||
"backup_controller_page_background_battery_info_ok": "OK",
|
||||
"backup_controller_page_background_battery_info_title": "Optimalizace baterie",
|
||||
"backup_controller_page_background_charging": "Pouze během nabíjení",
|
||||
"backup_controller_page_background_configure_error": "Nepodařilo se nakonfigurovat službu na pozadí",
|
||||
"backup_controller_page_background_delay": "Zpoždění zálohování nových zdrojů: {}",
|
||||
"backup_controller_page_background_delay": "Zpoždění zálohování nových médií: {}",
|
||||
"backup_controller_page_background_description": "Povolte službu na pozadí pro automatické zálohování všech nových aktiv bez nutnosti otevření aplikace",
|
||||
"backup_controller_page_background_is_off": "Automatické zálohování na pozadí je vypnuto",
|
||||
"backup_controller_page_background_is_on": "Automatické zálohování na pozadí je zapnuto",
|
||||
"backup_controller_page_background_turn_off": "Zakázat službu na pozadí",
|
||||
"backup_controller_page_background_turn_on": "Povolit službu na pozadí",
|
||||
"backup_controller_page_background_turn_off": "Vypnout zálohování na pozadí",
|
||||
"backup_controller_page_background_turn_on": "Povolit zálohování na pozadí",
|
||||
"backup_controller_page_background_wifi": "Jen na WiFi",
|
||||
"backup_controller_page_backup": "Zálohování",
|
||||
"backup_controller_page_backup_selected": "Vybrané: ",
|
||||
"backup_controller_page_backup_sub": "Zálohování fotografií a videí",
|
||||
"backup_controller_page_cancel": "Zrušit",
|
||||
"backup_controller_page_backup_sub": "Zálohované fotografie a videa",
|
||||
"backup_controller_page_cancel": "Zastavit",
|
||||
"backup_controller_page_created": "Vytvořeno: {}",
|
||||
"backup_controller_page_desc_backup": "Zapněte zálohování na popředí, aby se nové položky automaticky nahrávaly na server při otevření aplikace.",
|
||||
"backup_controller_page_excluded": "Vyloučeno: ",
|
||||
@@ -54,8 +66,8 @@
|
||||
"backup_controller_page_id": "ID: {}",
|
||||
"backup_controller_page_info": "Informace o zálohování",
|
||||
"backup_controller_page_none_selected": "Žádné vybrané",
|
||||
"backup_controller_page_remainder": "Zbytek",
|
||||
"backup_controller_page_remainder_sub": "Zbývající fotografie a alba, která se mají zálohovat z výběru",
|
||||
"backup_controller_page_remainder": "Zůstává",
|
||||
"backup_controller_page_remainder_sub": "Zbývající fotografie a videa, která se mají zálohovat z vybraných alb",
|
||||
"backup_controller_page_select": "Vybrat",
|
||||
"backup_controller_page_server_storage": "Serverové úložiště",
|
||||
"backup_controller_page_start_backup": "Spustit zálohování",
|
||||
@@ -65,11 +77,11 @@
|
||||
"backup_controller_page_to_backup": "Alba, která mají být zálohována",
|
||||
"backup_controller_page_total": "Celkem",
|
||||
"backup_controller_page_total_sub": "Všechny jedinečné fotografie a videa z vybraných alb",
|
||||
"backup_controller_page_turn_off": "Zakázat zálohování na popředí",
|
||||
"backup_controller_page_turn_off": "Vypnout zálohování na popředí",
|
||||
"backup_controller_page_turn_on": "Povolit zálohování na popředí",
|
||||
"backup_controller_page_uploading_file_info": "Nahrávání informací o souborech",
|
||||
"backup_err_only_album": "Nelze odstranit pouze album",
|
||||
"backup_info_card_assets": "položky",
|
||||
"backup_controller_page_uploading_file_info": "Nahrávaný soubor",
|
||||
"backup_err_only_album": "Nelze odstranit jediné vybrané album",
|
||||
"backup_info_card_assets": "položek",
|
||||
"cache_settings_album_thumbnails": "Náhledy stránek knihovny (položek {})",
|
||||
"cache_settings_clear_cache_button": "Vymazat vyrovnávací paměť",
|
||||
"cache_settings_clear_cache_button_title": "Vymaže vyrovnávací paměť aplikace. To výrazně ovlivní výkon aplikace, dokud se vyrovnávací paměť neobnoví.",
|
||||
@@ -83,20 +95,33 @@
|
||||
"cache_settings_subtitle": "Ovládání chování mobilní aplikace Immich v mezipaměti",
|
||||
"cache_settings_thumbnail_size": "Velikost vyrovnávací paměti náhledů (položek {})",
|
||||
"cache_settings_title": "Nastavení vyrovnávací paměti",
|
||||
"change_password_form_confirm_password": "Potvrďte heslo",
|
||||
"change_password_form_description": "Dobrý den, {firstName} {lastName},\n\nJe to buď poprvé, co se přihlašujete do systému, nebo byl vytvořen požadavek na změnu hesla. Zadejte níže, prosím, nové heslo.",
|
||||
"change_password_form_new_password": "Nové heslo",
|
||||
"change_password_form_password_mismatch": "Hesla se neshodují",
|
||||
"change_password_form_reenter_new_password": "Znovu zadejte nové heslo",
|
||||
"common_add_to_album": "Přidat do alba",
|
||||
"common_change_password": "Změnit heslo",
|
||||
"common_create_new_album": "Vytvořit nové album",
|
||||
"common_server_error": "Zkontrolujte připojení k internetu. Ujistěte se, že server je dostupný a aplikace/server jsou v kompatibilní verzi.",
|
||||
"common_shared": "Sdílené",
|
||||
"control_bottom_app_bar_add_to_album": "Přidat do alba",
|
||||
"control_bottom_app_bar_album_info": "{} položky",
|
||||
"control_bottom_app_bar_album_info": "{} položek",
|
||||
"control_bottom_app_bar_album_info_shared": "{} položky - sdílené",
|
||||
"control_bottom_app_bar_create_new_album": "Vytvořit nové album",
|
||||
"control_bottom_app_bar_delete": "Vymazat",
|
||||
"control_bottom_app_bar_favorite": "Oblíbené",
|
||||
"control_bottom_app_bar_share": "Sdílet",
|
||||
"create_album_page_untitled": "Bez názvu",
|
||||
"create_shared_album_page_create": "Vytvořit",
|
||||
"create_shared_album_page_share": "Sdílet",
|
||||
"create_shared_album_page_share_add_assets": "PŘIDAT",
|
||||
"create_shared_album_page_share_select_photos": "Vybrat fotografie",
|
||||
"daily_title_text_date": "EEEE, d MMMM",
|
||||
"daily_title_text_date_year": "EEEE, d MMMM y",
|
||||
"date_format": "EEEE, d MMMM y • H:mm",
|
||||
"curated_location_page_title": "Místa",
|
||||
"curated_object_page_title": "Věci",
|
||||
"daily_title_text_date": "EEEE, d. MMMM",
|
||||
"daily_title_text_date_year": "EEEE, d. MMMM y",
|
||||
"date_format": "EEEE, d. MMMM y • H:mm",
|
||||
"delete_dialog_alert": "Tyto položky budou trvale odstraněny z Immich a z vašeho zařízení.",
|
||||
"delete_dialog_cancel": "Zrušit",
|
||||
"delete_dialog_ok": "Vymazat",
|
||||
@@ -104,20 +129,34 @@
|
||||
"exif_bottom_sheet_description": "Přidat popis...",
|
||||
"exif_bottom_sheet_details": "PODROBNOSTI",
|
||||
"exif_bottom_sheet_location": "LOKALITA",
|
||||
"experimental_settings_new_asset_list_subtitle": "Probíhající práce",
|
||||
"experimental_settings_new_asset_list_subtitle": "Zpracovávám",
|
||||
"experimental_settings_new_asset_list_title": "Povolení experimentální mřížky fotografií",
|
||||
"experimental_settings_subtitle": "Používejte na vlastní riziko!",
|
||||
"experimental_settings_title": "Experimentální",
|
||||
"home_page_add_to_album_conflicts": "Přidány {added} položky do alba {album}. {failed} položky jsou již v albu.",
|
||||
"favorites_page_title": "Oblíbené",
|
||||
"home_page_add_to_album_conflicts": "Přidáno {added} položek do alba {album}. {failed} položek již je v albu.",
|
||||
"home_page_add_to_album_err_local": "Zatím není možné přidat lokální média do alb, přeskakuje se",
|
||||
"home_page_add_to_album_success": "Přidány položky {added} do alba {album}.",
|
||||
"home_page_building_timeline": "Vytváření časové osy",
|
||||
"home_page_favorite_err_local": "Zatím není možné zařadit lokální média mezi oblíbená, přeskakuje se",
|
||||
"home_page_first_time_notice": "Pokud aplikaci používáte poprvé, nezapomeňte si vybrat zálohovaná alba, aby se na časové ose mohly nacházet fotografie a videa z vybraných albech.",
|
||||
"image_viewer_page_state_provider_download_error": "Chyba stahování",
|
||||
"image_viewer_page_state_provider_download_success": "Stahování bylo úspěšné",
|
||||
"library_page_albums": "Alba",
|
||||
"library_page_device_albums": "Alba v zařízení",
|
||||
"library_page_favorites": "Oblíbené",
|
||||
"library_page_new_album": "Nové album",
|
||||
"login_form_button_text": "Přihlášení",
|
||||
"library_page_sharing": "Sdílení",
|
||||
"library_page_sort_created": "Naposledy vytvořené",
|
||||
"library_page_sort_title": "Podle názvu alba",
|
||||
"login_form_api_exception": "Výjimka API. Zkontrolujte URL serveru a zkuste to znovu.",
|
||||
"login_form_button_text": "Přihlásit se",
|
||||
"login_form_email_hint": "tvůjmail@email.com",
|
||||
"login_form_endpoint_hint": "http://ip-tvého-serveru:port/api",
|
||||
"login_form_endpoint_url": "URL adresa serveru",
|
||||
"login_form_err_http": "Prosím, uveďte http:// nebo https://",
|
||||
"login_form_err_invalid_email": "Neplatný e-mail",
|
||||
"login_form_err_invalid_url": "Neplatná URL",
|
||||
"login_form_err_leading_whitespace": "Úvodní mezera",
|
||||
"login_form_err_trailing_whitespace": "Koncová mezera",
|
||||
"login_form_failed_get_oauth_server_config": "Chyba přihlášení pomocí OAuth, zkontrolujte adresu URL serveru",
|
||||
@@ -125,24 +164,57 @@
|
||||
"login_form_failed_login": "Chyba přihlášení, zkontrolujte url adresu serveru, e-mail a heslo.",
|
||||
"login_form_label_email": "E-mail",
|
||||
"login_form_label_password": "Heslo",
|
||||
"login_form_next_button": "Další",
|
||||
"login_form_password_hint": "heslo",
|
||||
"login_form_save_login": "Zůstat přihlášen",
|
||||
"login_form_server_empty": "Zadejte URL serveru.",
|
||||
"login_form_server_error": "Není možné se připojit k serveru.",
|
||||
"monthly_title_text_date_format": "LLLL y",
|
||||
"motion_photos_page_title": "Pohyblivé fotky",
|
||||
"notification_permission_dialog_cancel": "Zrušit",
|
||||
"notification_permission_dialog_content": "Chcete-li povolit oznámení, přejděte do Nastavení a vyberte možnost povolit.",
|
||||
"notification_permission_dialog_settings": "Nastavení",
|
||||
"notification_permission_list_tile_content": "Udělte oprávnění k aktivaci oznámení.",
|
||||
"notification_permission_list_tile_enable_button": "Povolit oznámení",
|
||||
"notification_permission_list_tile_title": "Povolení oznámení",
|
||||
"permission_onboarding_continue_anyway": "Přesto pokračovat",
|
||||
"permission_onboarding_get_started": "Začít",
|
||||
"permission_onboarding_go_to_settings": "Přejít do nastavení",
|
||||
"permission_onboarding_grant_permission": "Povolit přístup",
|
||||
"permission_onboarding_log_out": "Odhlásit se",
|
||||
"permission_onboarding_permission_denied": "Přístup odepřen. Pro používání Immich, je nutné povolit přístup k fotkám a videím v nastavení.",
|
||||
"permission_onboarding_permission_granted": "Přístup povolen! Vše je připraveno.",
|
||||
"permission_onboarding_permission_limited": "Přístup omezen. Chcete-li používat Immich k zálohování a správě celé vaší kolekci galerií, povolte přístup k fotkám a videím v Nastavení.",
|
||||
"permission_onboarding_request": "Immich potřebuje přístup k zobrazení vašich fotek a videí.",
|
||||
"profile_drawer_app_logs": "Logy",
|
||||
"profile_drawer_client_server_up_to_date": "Klient a server jsou aktuální",
|
||||
"profile_drawer_settings": "Nastavení",
|
||||
"profile_drawer_sign_out": "Odhlásit se",
|
||||
"recently_added_page_title": "Nedávno přidané",
|
||||
"search_bar_hint": "Prohledejte své obrázky",
|
||||
"search_page_no_objects": "Žádné informace o objektech",
|
||||
"search_page_no_places": "Žádné informace o místě",
|
||||
"search_page_categories": "Kategorie",
|
||||
"search_page_favorites": "Oblíbené",
|
||||
"search_page_motion_photos": "Pohyblivé fotky",
|
||||
"search_page_no_objects": "Informace o objektech nejsou k dispozici",
|
||||
"search_page_no_places": "Informace o místě nejsou k dispozici",
|
||||
"search_page_places": "Místa",
|
||||
"search_page_recently_added": "Nedávno přidané",
|
||||
"search_page_screenshots": "Snímky obrazovky",
|
||||
"search_page_selfies": "Selfie",
|
||||
"search_page_things": "Věci",
|
||||
"search_page_videos": "Videa",
|
||||
"search_page_view_all_button": "Zobrazit vše",
|
||||
"search_page_your_activity": "Vaše aktivita",
|
||||
"search_result_page_new_search_hint": "Nové vyhledávání",
|
||||
"search_suggestion_list_smart_search_hint_1": "Ve výchozím nastavení je chytré vyhledávání zapnuto, pro vyhledávání metadat použijte syntaxi",
|
||||
"search_suggestion_list_smart_search_hint_2": "m:vaše-vyhledávaná-fráze",
|
||||
"select_additional_user_for_sharing_page_suggestions": "Návrhy",
|
||||
"select_user_for_sharing_page_err_album": "Nepodařilo se vytvořit album",
|
||||
"select_user_for_sharing_page_share_suggestions": "Návrhy",
|
||||
"server_info_box_app_version": "Verze aplikace",
|
||||
"server_info_box_server_version": "Verze serveru",
|
||||
"setting_image_viewer_help": "V prohlížeči detailů se nejprve načte malá miniatura, poté se načte náhled střední velikosti (je-li povolen) a nakonec se načte originál (je-li povolen).",
|
||||
"setting_image_viewer_original_subtitle": "Umožňuje načíst původní obrázek v plném rozlišení (velký!). Zakázat pro snížení používání dat (v síti iv mezipaměti zařízení).",
|
||||
"setting_image_viewer_original_subtitle": "Umožňuje načíst původní obrázek v plném rozlišení (velký!). Zakázat pro snížení využití dat (v síti i v mezipaměti zařízení).",
|
||||
"setting_image_viewer_original_title": "Načíst původní obrázek",
|
||||
"setting_image_viewer_preview_subtitle": "Umožňuje načíst obrázek se středním rozlišením. Zakažte, pokud chcete přímo načíst originál nebo použít pouze miniaturu.",
|
||||
"setting_image_viewer_preview_title": "Načíst náhled obrázku",
|
||||
@@ -156,9 +228,9 @@
|
||||
"setting_notifications_single_progress_title": "Zobrazit průběh detailů zálohování na pozadí",
|
||||
"setting_notifications_subtitle": "Přizpůsobení předvoleb oznámení",
|
||||
"setting_notifications_title": "Oznámení",
|
||||
"setting_notifications_total_progress_subtitle": "Celkový průběh nahrávání (hotové/celkové položky)",
|
||||
"setting_notifications_total_progress_subtitle": "Celkový průběh nahrávání (nahraných/celkově)",
|
||||
"setting_notifications_total_progress_title": "Zobrazit celkový průběh zálohování na pozadí",
|
||||
"setting_pages_app_bar_settings": "nastavení",
|
||||
"setting_pages_app_bar_settings": "Nastavení",
|
||||
"settings_require_restart": "Pro použití tohoto nastavení restartujte Immich",
|
||||
"share_add": "Přidat",
|
||||
"share_add_photos": "Přidat fotografie",
|
||||
@@ -166,19 +238,19 @@
|
||||
"share_create_album": "Vytvořit album",
|
||||
"share_dialog_preparing": "Připravuji...",
|
||||
"share_invite": "Pozvat do alba",
|
||||
"sharing_page_album": "Shared albums",
|
||||
"sharing_page_album": "Sdílená alba",
|
||||
"sharing_page_description": "Vytvářejte sdílená alba a sdílejte fotografie a videa s lidmi ve vaší síti.",
|
||||
"sharing_page_empty_list": "Prázný dopis",
|
||||
"sharing_page_empty_list": "PRÁZDNÝ SEZNAM",
|
||||
"sharing_silver_appbar_create_shared_album": "Vytvořit sdílené album",
|
||||
"sharing_silver_appbar_share_partner": "Sdílet s partnerem",
|
||||
"tab_controller_nav_library": "Knihovna",
|
||||
"tab_controller_nav_photos": "Fotografie",
|
||||
"tab_controller_nav_search": "Vyhledávání",
|
||||
"tab_controller_nav_sharing": "Sdílení",
|
||||
"theme_setting_asset_list_storage_indicator_title": "Zobrazit indikátor úložiště na dlaždicích zdrojů",
|
||||
"theme_setting_asset_list_tiles_per_row_title": "Počet aktiv na řádek ({})",
|
||||
"theme_setting_asset_list_storage_indicator_title": "Zobrazit indikátor úložiště na dlaždicích položek",
|
||||
"theme_setting_asset_list_tiles_per_row_title": "Počet položek na řádek ({})",
|
||||
"theme_setting_dark_mode_switch": "Tmavé téma",
|
||||
"theme_setting_image_viewer_quality_subtitle": "Přizpůsobení kvality prohlížeče detailů",
|
||||
"theme_setting_image_viewer_quality_subtitle": "Přizpůsobení kvality detailů prohlížeče obrázků",
|
||||
"theme_setting_image_viewer_quality_title": "Kvalita prohlížeče obrázků",
|
||||
"theme_setting_system_theme_switch": "Automaticky (podle systemového nastavení)",
|
||||
"theme_setting_theme_subtitle": "Vyberte nastavení tématu aplikace",
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
{
|
||||
"add_to_album_bottom_sheet_added": "Tilføjet til {album}",
|
||||
"add_to_album_bottom_sheet_already_exists": "Allerede i {album}",
|
||||
"album_info_card_backup_album_excluded": "EKSKLUDERET",
|
||||
"album_info_card_backup_album_included": "INKLUDERET",
|
||||
"album_thumbnail_card_item": "1 genstand",
|
||||
"album_thumbnail_card_items": "{} genstande",
|
||||
"album_thumbnail_card_shared": ". Delt",
|
||||
"album_thumbnail_owned": "Ejet",
|
||||
"album_thumbnail_shared_by": "Delt af {}",
|
||||
"album_viewer_appbar_share_delete": "Slet album",
|
||||
"album_viewer_appbar_share_err_delete": "Fejlede sletning af album",
|
||||
"album_viewer_appbar_share_err_leave": "Fejlede i at forlade album",
|
||||
@@ -12,6 +16,11 @@
|
||||
"album_viewer_appbar_share_leave": "Forlad album",
|
||||
"album_viewer_appbar_share_remove": "Fjern fra album",
|
||||
"album_viewer_page_share_add_users": "Tilføj brugere",
|
||||
"all_videos_page_title": "Videoer",
|
||||
"asset_list_layout_settings_dynamic_layout_title": "Dynamisk layout",
|
||||
"asset_list_layout_settings_group_by": "Gruppér elementer pr. ",
|
||||
"asset_list_layout_settings_group_by_month": "Måned",
|
||||
"asset_list_layout_settings_group_by_month_day": "Måned + dag",
|
||||
"asset_list_settings_subtitle": "Indstillinger for billedgitterlayout",
|
||||
"asset_list_settings_title": "Billedgitter",
|
||||
"backup_album_selection_page_albums_device": "Albummer på enhed ({})",
|
||||
@@ -21,22 +30,25 @@
|
||||
"backup_album_selection_page_selection_info": "Oplysninger om valgte",
|
||||
"backup_album_selection_page_total_assets": "Samlede unikke elementer",
|
||||
"backup_all": "Alt",
|
||||
"backup_background_service_backup_failed_message": "Backup af billeder og videoer fejlede. Forsøger igen...",
|
||||
"backup_background_service_backup_failed_message": "Backup af elementer fejlede. Forsøger igen...",
|
||||
"backup_background_service_connection_failed_message": "Forbindelsen til serveren blev tabt. Forsøger igen...",
|
||||
"backup_background_service_current_upload_notification": "Uploader {}",
|
||||
"backup_background_service_default_notification": "Checking for new assets…",
|
||||
"backup_background_service_default_notification": "Søger efter nye elementer...",
|
||||
"backup_background_service_error_title": "Fejl med backup",
|
||||
"backup_background_service_in_progress_notification": "Tager backup af dine billeder og videoer...",
|
||||
"backup_background_service_upload_failure_notification": "Failed to upload {}",
|
||||
"backup_background_service_in_progress_notification": "Tager backup af dine elementer...",
|
||||
"backup_background_service_upload_failure_notification": "Fejlede med uploade af {}",
|
||||
"backup_controller_page_albums": "Sikkerhedskopiér albummer",
|
||||
"backup_controller_page_background_app_refresh_disabled_content": "Slå baggrundsopdatering af applikationen til i Indstillinger > Generelt > Baggrundsopdatering af applikationer, for at bruge baggrundsbackup.",
|
||||
"backup_controller_page_background_app_refresh_disabled_title": "Baggrundsopdatering af app er slået fra",
|
||||
"backup_controller_page_background_app_refresh_enable_button_text": "Gå til indstillinger",
|
||||
"backup_controller_page_background_battery_info_link": "Vis mig hvordan",
|
||||
"backup_controller_page_background_battery_info_message": "For den bedste oplevelse med baggrundsbackup, bør du slå batterioptimering, der begrænder baggrundsaktivitet, fra.\n\nSiden dette er afhængigt af enheden, bør du undersøge denne information leveret af din enheds producent.",
|
||||
"backup_controller_page_background_battery_info_ok": "OK",
|
||||
"backup_controller_page_background_battery_info_title": "Batterioptimering",
|
||||
"backup_controller_page_background_charging": "Kun under opladning",
|
||||
"backup_controller_page_background_configure_error": "Fejlede konfigureringen af baggrundsbackup",
|
||||
"backup_controller_page_background_delay": "Udskyd backup af nye billeder og videoer: {}",
|
||||
"backup_controller_page_background_description": "Slå baggrundsbackup til, for automatisk at tage backup af nye billeder og videoer, uden at skulle åbne appen",
|
||||
"backup_controller_page_background_delay": "Udskyd backup af nye elementer: {}",
|
||||
"backup_controller_page_background_description": "Slå baggrundsbackup til, for automatisk at tage backup af nye elementer, uden at skulle åbne appen",
|
||||
"backup_controller_page_background_is_off": "Automatisk baggrundsbackup er slået fra",
|
||||
"backup_controller_page_background_is_on": "Automatisk baggrundsbackup er slået til",
|
||||
"backup_controller_page_background_turn_off": "Slå baggrundsbackup fra",
|
||||
@@ -70,30 +82,43 @@
|
||||
"backup_controller_page_uploading_file_info": "Uploader filinformation",
|
||||
"backup_err_only_album": "Kan ikke slette det eneste album",
|
||||
"backup_info_card_assets": "elementer",
|
||||
"cache_settings_album_thumbnails": "Biblioteksminiaturebilleder ({} billeder og videoer)",
|
||||
"cache_settings_album_thumbnails": "Biblioteksminiaturebilleder ({} elementer)",
|
||||
"cache_settings_clear_cache_button": "Fjern cache",
|
||||
"cache_settings_clear_cache_button_title": "Fjern appens cache. Dette vil i stor grad påvirke appens ydeevne indtil cachen er genopbygget.",
|
||||
"cache_settings_image_cache_size": "Størrelse af billedecache ({} billeder og videoer)",
|
||||
"cache_settings_image_cache_size": "Størrelse af billedecache ({} elementer)",
|
||||
"cache_settings_statistics_album": "Biblioteksminiaturer",
|
||||
"cache_settings_statistics_assets": "{} billeder og videoer ({})",
|
||||
"cache_settings_statistics_assets": "{} elementer ({})",
|
||||
"cache_settings_statistics_full": "Fulde billeder",
|
||||
"cache_settings_statistics_shared": "Miniaturebilleder til delte albummer",
|
||||
"cache_settings_statistics_thumbnail": "Miniaturebilleder",
|
||||
"cache_settings_statistics_title": "Cacheforbrug",
|
||||
"cache_settings_subtitle": "Håndter cache-adfærden for Immich-appen.",
|
||||
"cache_settings_thumbnail_size": "Størrelse af miniaturebillede cache ({} billeder og videoer)",
|
||||
"cache_settings_thumbnail_size": "Størrelse af miniaturebillede cache ({} elementer)",
|
||||
"cache_settings_title": "Cache-indstillinger",
|
||||
"change_password_form_confirm_password": "Bekræft kodeord",
|
||||
"change_password_form_description": "Hej {firstName} {lastName},\n\nDette er enten første gang du logger ind eller også er der lavet en anmodning om at ændre dit kodeord. Indtast venligst et nyt kodeord nedenfor.",
|
||||
"change_password_form_new_password": "Nyt kodeord",
|
||||
"change_password_form_password_mismatch": "Kodeord er ikke ens",
|
||||
"change_password_form_reenter_new_password": "Gentag nyt kodeord",
|
||||
"common_add_to_album": "Tilføj til album",
|
||||
"common_change_password": "Skift kodeord",
|
||||
"common_create_new_album": "Opret et nyt album",
|
||||
"common_server_error": "Tjek din internetforbindelse, sørg for at serveren er tilgængelig og at app- og serversioner er kompatible.",
|
||||
"common_shared": "Delt",
|
||||
"control_bottom_app_bar_add_to_album": "Tilføj til album",
|
||||
"control_bottom_app_bar_album_info": "{} genstande",
|
||||
"control_bottom_app_bar_album_info_shared": "{} genstande • Delt",
|
||||
"control_bottom_app_bar_create_new_album": "Opret nyt album",
|
||||
"control_bottom_app_bar_delete": "Slet",
|
||||
"control_bottom_app_bar_favorite": "Favorit",
|
||||
"control_bottom_app_bar_share": "Del",
|
||||
"create_album_page_untitled": "Uden titel",
|
||||
"create_shared_album_page_create": "Opret",
|
||||
"create_shared_album_page_share": "Del",
|
||||
"create_shared_album_page_share_add_assets": "TILFØJ ELEMENT",
|
||||
"create_shared_album_page_share_select_photos": "Vælg billeder",
|
||||
"curated_location_page_title": "Steder",
|
||||
"curated_object_page_title": "Ting",
|
||||
"daily_title_text_date": "E, dd MMM",
|
||||
"daily_title_text_date_year": "E, dd MMM, yyyy",
|
||||
"date_format": "E d. LLL y • hh:mm",
|
||||
@@ -108,17 +133,23 @@
|
||||
"experimental_settings_new_asset_list_title": "Aktiver eksperimentelt fotogitter",
|
||||
"experimental_settings_subtitle": "Brug på eget ansvar!",
|
||||
"experimental_settings_title": "Eksperimentelle",
|
||||
"favorites_page_title": "Favorites",
|
||||
"home_page_add_to_album_conflicts": "Tilføjede {added} billeder og videoer til album {album}. {failed} billeder og videoer er allerede i albummet.",
|
||||
"home_page_add_to_album_success": "Tilføjede {added} billeder og videoer til album {album}.",
|
||||
"home_page_building_timeline": "Building the timeline",
|
||||
"home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s).",
|
||||
"favorites_page_title": "Favoritter",
|
||||
"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_success": "Tilføjede {added} elementer til album {album}.",
|
||||
"home_page_building_timeline": "Bygger tidslinjen",
|
||||
"home_page_favorite_err_local": "Kan endnu ikke gøre lokale elementer til favoritter. Springer over..",
|
||||
"home_page_first_time_notice": "Hvis dette er din første gang i appen, bedes du vælge en backup af albummer så tidlinjen kan blive fyldt med billeder og videoer fra albummerne.",
|
||||
"image_viewer_page_state_provider_download_error": "Fejl ved download",
|
||||
"image_viewer_page_state_provider_download_success": "Download succesfuld",
|
||||
"library_page_albums": "Albummer",
|
||||
"library_page_favorites": "Favorites",
|
||||
"library_page_device_albums": "Albummer på enhed",
|
||||
"library_page_favorites": "Favoritter",
|
||||
"library_page_new_album": "Nyt album",
|
||||
"library_page_sharing": "Sharing",
|
||||
"library_page_sort_created": "Most recently created",
|
||||
"library_page_sort_title": "Album title",
|
||||
"library_page_sharing": "Delte",
|
||||
"library_page_sort_created": "Senest oprettet",
|
||||
"library_page_sort_title": "Albumtitel",
|
||||
"login_form_api_exception": "API-undtagelse. Tjek serverens URL og prøv igen. ",
|
||||
"login_form_button_text": "Log ind",
|
||||
"login_form_email_hint": "din-e-mail@e-mail.com",
|
||||
"login_form_endpoint_hint": "http://din-server-ip:port/api",
|
||||
@@ -133,22 +164,55 @@
|
||||
"login_form_failed_login": "Der opstod en vejl ved at logge ind. Tjek server webadressen, e-mailen og kodeordet",
|
||||
"login_form_label_email": "E-mail",
|
||||
"login_form_label_password": "Kodeord",
|
||||
"login_form_next_button": "Næste",
|
||||
"login_form_password_hint": "kodeord",
|
||||
"login_form_save_login": "Forbliv logget ind",
|
||||
"login_form_server_empty": "Indtast server-URL.",
|
||||
"login_form_server_error": "Kunne ikke forbinde til serveren.",
|
||||
"monthly_title_text_date_format": "MMMM y",
|
||||
"motion_photos_page_title": "Bevægelsesbilleder",
|
||||
"notification_permission_dialog_cancel": "Annuller",
|
||||
"notification_permission_dialog_content": "Gå til indstillinger for at slå notifikationer til.",
|
||||
"notification_permission_dialog_settings": "Indstillinger",
|
||||
"notification_permission_list_tile_content": "Tillad at bruge notifikationer.",
|
||||
"notification_permission_list_tile_enable_button": "Slå notifikationer til",
|
||||
"notification_permission_list_tile_title": "Notifikationstilladelser",
|
||||
"permission_onboarding_continue_anyway": "Fortsæt alligevel",
|
||||
"permission_onboarding_get_started": "Kom i gang",
|
||||
"permission_onboarding_go_to_settings": "Gå til indstillinger",
|
||||
"permission_onboarding_grant_permission": "Giv tilladelse",
|
||||
"permission_onboarding_log_out": "Log ud",
|
||||
"permission_onboarding_permission_denied": "Tilladelse afvist. For at bruge Immich, skal der gives tilladelse til at se billeder og videoer i indstillinger.",
|
||||
"permission_onboarding_permission_granted": "Tilladelse givet! Du er nu klar.",
|
||||
"permission_onboarding_permission_limited": "Tilladelse begrænset. For at lade Immich lave backup og styre hele dit galleri, skal der gives tilladelse til billeder og videoer i indstillinger.",
|
||||
"permission_onboarding_request": "Immich kræver tilliadelse til at se dine billeder og videoer.",
|
||||
"profile_drawer_app_logs": "Log",
|
||||
"profile_drawer_client_server_up_to_date": "Klient og server er ajour",
|
||||
"profile_drawer_settings": "Indstillinger",
|
||||
"profile_drawer_sign_out": "Log ud",
|
||||
"recently_added_page_title": "Nyligt tilføjet",
|
||||
"search_bar_hint": "Søg i dine billeder",
|
||||
"search_page_categories": "Kategorier",
|
||||
"search_page_favorites": "Favoritter",
|
||||
"search_page_motion_photos": "Bevægelsesbilleder",
|
||||
"search_page_no_objects": "Ingen elementer er tilgængelige",
|
||||
"search_page_no_places": "Ingen placeringsinformation er tilgængelig",
|
||||
"search_page_places": "Steder",
|
||||
"search_page_recently_added": "Nyligt tilføjet",
|
||||
"search_page_screenshots": "Skærmbilleder",
|
||||
"search_page_selfies": "Selfier",
|
||||
"search_page_things": "Ting",
|
||||
"search_page_videos": "Videoer",
|
||||
"search_page_view_all_button": "Vis alt",
|
||||
"search_page_your_activity": "Din aktivitet",
|
||||
"search_result_page_new_search_hint": "Ny søgning",
|
||||
"search_suggestion_list_smart_search_hint_1": "Smart søgnining er slået til som standard. For at søge efter metadata brug syntaksen",
|
||||
"search_suggestion_list_smart_search_hint_2": "m:dit-søgeord",
|
||||
"select_additional_user_for_sharing_page_suggestions": "Anbefalinger",
|
||||
"select_user_for_sharing_page_err_album": "Fejlede i at oprette et nyt album",
|
||||
"select_user_for_sharing_page_share_suggestions": "Anbefalinger",
|
||||
"server_info_box_app_version": "Applikationsversion",
|
||||
"server_info_box_server_version": "Serverversion ",
|
||||
"setting_image_viewer_help": "Detaljeret visning indlæser miniaturebilleder først. Herefter indlæses mediumstørrelse forhåndsvisning af billedet (hvis dette er slået til), for til sidst at vise originalen (hvis dette er slået til).",
|
||||
"setting_image_viewer_original_subtitle": "Slå indlæsning af originalbillede i fuld størrelse til (stort!). Deaktiver for at reducere dataforbruget (både på netværket og for enhedscache).",
|
||||
"setting_image_viewer_original_title": "Indlæs originalbillede",
|
||||
@@ -160,11 +224,11 @@
|
||||
"setting_notifications_notify_minutes": "{} minutter",
|
||||
"setting_notifications_notify_never": "aldrig",
|
||||
"setting_notifications_notify_seconds": "{} sekunder",
|
||||
"setting_notifications_single_progress_subtitle": "Detaljeret uploadstatus pr. billed og video",
|
||||
"setting_notifications_single_progress_subtitle": "Detaljeret uploadstatus pr. element",
|
||||
"setting_notifications_single_progress_title": "Vis detaljeret baggrundsuploadstatus",
|
||||
"setting_notifications_subtitle": "Tilpas dine notifikationspræferencer",
|
||||
"setting_notifications_title": "Notifikationer",
|
||||
"setting_notifications_total_progress_subtitle": "Samlet uploadstatus (færdige/samlede billeder og videoer)",
|
||||
"setting_notifications_total_progress_subtitle": "Samlet uploadstatus (færdige/samlet antal elementer)",
|
||||
"setting_notifications_total_progress_title": "Vis samlet baggrundsuploadstatus",
|
||||
"setting_pages_app_bar_settings": "Indstillinger",
|
||||
"settings_require_restart": "Genstart venligst Immich for at anvende denne ændring",
|
||||
@@ -184,7 +248,7 @@
|
||||
"tab_controller_nav_search": "Søg",
|
||||
"tab_controller_nav_sharing": "Deling",
|
||||
"theme_setting_asset_list_storage_indicator_title": "Vis opbevaringsindikator på filer",
|
||||
"theme_setting_asset_list_tiles_per_row_title": "Antal billeder og videoer per række ({})",
|
||||
"theme_setting_asset_list_tiles_per_row_title": "Antal elementer per række ({})",
|
||||
"theme_setting_dark_mode_switch": "Mørk tilstand",
|
||||
"theme_setting_image_viewer_quality_subtitle": "Juster kvaliteten i billedfremviseren",
|
||||
"theme_setting_image_viewer_quality_title": "Billedfremviserkvalitet",
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
{
|
||||
"add_to_album_bottom_sheet_added": "Added to {album}",
|
||||
"add_to_album_bottom_sheet_already_exists": "Already in {album}",
|
||||
"album_info_card_backup_album_excluded": "AUSGESCHLOSSEN",
|
||||
"album_info_card_backup_album_included": "EINGESCHLOSSEN",
|
||||
"album_thumbnail_card_item": "1 Element",
|
||||
"album_thumbnail_card_items": "{} Elemente",
|
||||
"album_thumbnail_card_shared": " · Geteilt",
|
||||
"album_thumbnail_owned": "Owned",
|
||||
"album_thumbnail_shared_by": "Shared by {}",
|
||||
"album_viewer_appbar_share_delete": "Album löschen",
|
||||
"album_viewer_appbar_share_err_delete": "Album konnte nicht gelöscht werden",
|
||||
"album_viewer_appbar_share_err_leave": "Album konnte nicht verlassen werden",
|
||||
@@ -12,6 +16,11 @@
|
||||
"album_viewer_appbar_share_leave": "Album verlassen",
|
||||
"album_viewer_appbar_share_remove": "Entferne vom Album",
|
||||
"album_viewer_page_share_add_users": "Nutzer hinzufügen",
|
||||
"all_videos_page_title": "Videos",
|
||||
"asset_list_layout_settings_dynamic_layout_title": "Dynamic layout",
|
||||
"asset_list_layout_settings_group_by": "Group assets by",
|
||||
"asset_list_layout_settings_group_by_month": "Month",
|
||||
"asset_list_layout_settings_group_by_month_day": "Month + day",
|
||||
"asset_list_settings_subtitle": "Photo grid layout settings",
|
||||
"asset_list_settings_title": "Photo Grid",
|
||||
"backup_album_selection_page_albums_device": "Alben auf dem Gerät ({})",
|
||||
@@ -29,6 +38,9 @@
|
||||
"backup_background_service_in_progress_notification": "Backing up your assets…",
|
||||
"backup_background_service_upload_failure_notification": "Failed to upload {}",
|
||||
"backup_controller_page_albums": "Gesicherte Alben",
|
||||
"backup_controller_page_background_app_refresh_disabled_content": "Enable background app refresh in Settings > General > Background App Refresh in order to use background backup.",
|
||||
"backup_controller_page_background_app_refresh_disabled_title": "Background app refresh disabled",
|
||||
"backup_controller_page_background_app_refresh_enable_button_text": "Go to settings",
|
||||
"backup_controller_page_background_battery_info_link": "Show me how",
|
||||
"backup_controller_page_background_battery_info_message": "For the best background backup experience, please disable any battery optimizations restricting background activity for Immich.\n\nSince this is device-specific, please lookup the required information for your device manufacturer.",
|
||||
"backup_controller_page_background_battery_info_ok": "OK",
|
||||
@@ -83,17 +95,30 @@
|
||||
"cache_settings_subtitle": "Control the caching behaviour of the Immich mobile application",
|
||||
"cache_settings_thumbnail_size": "Thumbnail cache size ({} assets)",
|
||||
"cache_settings_title": "Caching Settings",
|
||||
"change_password_form_confirm_password": "Confirm Password",
|
||||
"change_password_form_description": "Hi {firstName} {lastName},\n\nThis is either the first time you are signing into the system or a request has been made to change your password. Please enter the new password below.",
|
||||
"change_password_form_new_password": "New Password",
|
||||
"change_password_form_password_mismatch": "Passwords do not match",
|
||||
"change_password_form_reenter_new_password": "Re-enter New Password",
|
||||
"common_add_to_album": "Add to album",
|
||||
"common_change_password": "Change Password",
|
||||
"common_create_new_album": "Create new album",
|
||||
"common_server_error": "Please check your network connection, make sure the server is reachable and app/server versions are compatible.",
|
||||
"common_shared": "Shared",
|
||||
"control_bottom_app_bar_add_to_album": "Add to album",
|
||||
"control_bottom_app_bar_album_info": "{} items",
|
||||
"control_bottom_app_bar_album_info_shared": "{} items · Shared",
|
||||
"control_bottom_app_bar_create_new_album": "Neues Album erstellen",
|
||||
"control_bottom_app_bar_delete": "Löschen",
|
||||
"control_bottom_app_bar_favorite": "Favorite",
|
||||
"control_bottom_app_bar_share": "Teilen",
|
||||
"create_album_page_untitled": "Unbenannt",
|
||||
"create_shared_album_page_create": "Erstellen",
|
||||
"create_shared_album_page_share": "Teilen",
|
||||
"create_shared_album_page_share_add_assets": "ELEMENTE HINZUFÜGEN",
|
||||
"create_shared_album_page_share_select_photos": "Fotos auswählen",
|
||||
"curated_location_page_title": "Places",
|
||||
"curated_object_page_title": "Things",
|
||||
"daily_title_text_date": "E, dd MMM",
|
||||
"daily_title_text_date_year": "E, dd MMM, yyyy",
|
||||
"date_format": "E d. LLL y • hh:mm",
|
||||
@@ -110,15 +135,21 @@
|
||||
"experimental_settings_title": "Experimentell",
|
||||
"favorites_page_title": "Favorites",
|
||||
"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_success": "Added {added} assets to album {album}.",
|
||||
"home_page_building_timeline": "Building the timeline",
|
||||
"home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
|
||||
"home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s).",
|
||||
"image_viewer_page_state_provider_download_error": "Download Error",
|
||||
"image_viewer_page_state_provider_download_success": "Download Success",
|
||||
"library_page_albums": "Alben",
|
||||
"library_page_device_albums": "Albums on Device",
|
||||
"library_page_favorites": "Favorites",
|
||||
"library_page_new_album": "Neues Album",
|
||||
"library_page_sharing": "Sharing",
|
||||
"library_page_sort_created": "Most recently created",
|
||||
"library_page_sort_title": "Album title",
|
||||
"login_form_api_exception": "API exception. Please check the server URL and try again.",
|
||||
"login_form_button_text": "Anmelden",
|
||||
"login_form_email_hint": "deine@email.de",
|
||||
"login_form_endpoint_hint": "http://deine-server-ip:port/api",
|
||||
@@ -133,22 +164,55 @@
|
||||
"login_form_failed_login": "Error logging you in, check server url, email and password",
|
||||
"login_form_label_email": "E-Mail",
|
||||
"login_form_label_password": "Passwort",
|
||||
"login_form_next_button": "Next",
|
||||
"login_form_password_hint": "password",
|
||||
"login_form_save_login": "Angemeldet bleiben",
|
||||
"login_form_server_empty": "Enter a server URL.",
|
||||
"login_form_server_error": "Could not connect to server.",
|
||||
"monthly_title_text_date_format": "MMMM y",
|
||||
"motion_photos_page_title": "Motion Photos",
|
||||
"notification_permission_dialog_cancel": "Cancel",
|
||||
"notification_permission_dialog_content": "To enable notifications, go to Settings and select allow.",
|
||||
"notification_permission_dialog_settings": "Settings",
|
||||
"notification_permission_list_tile_content": "Grant permission to enable notifications.",
|
||||
"notification_permission_list_tile_enable_button": "Enable Notifications",
|
||||
"notification_permission_list_tile_title": "Notification Permission",
|
||||
"permission_onboarding_continue_anyway": "Continue anyway",
|
||||
"permission_onboarding_get_started": "Get started",
|
||||
"permission_onboarding_go_to_settings": "Go to settings",
|
||||
"permission_onboarding_grant_permission": "Grant permission",
|
||||
"permission_onboarding_log_out": "Log out",
|
||||
"permission_onboarding_permission_denied": "Permission denied. To use Immich, grant photo and video permissions in Settings.",
|
||||
"permission_onboarding_permission_granted": "Permission granted! You are all set.",
|
||||
"permission_onboarding_permission_limited": "Permission limited. To let Immich backup and manage your entire gallery collection, grant photo and video permissions in Settings.",
|
||||
"permission_onboarding_request": "Immich requires permission to view your photos and videos.",
|
||||
"profile_drawer_app_logs": "Logs",
|
||||
"profile_drawer_client_server_up_to_date": "App und Server sind aktuell",
|
||||
"profile_drawer_settings": "Einstellungen",
|
||||
"profile_drawer_sign_out": "Abmelden",
|
||||
"recently_added_page_title": "Recently Added",
|
||||
"search_bar_hint": "Durchsuche deine Fotos",
|
||||
"search_page_categories": "Categories",
|
||||
"search_page_favorites": "Favorites",
|
||||
"search_page_motion_photos": "Motion Photos",
|
||||
"search_page_no_objects": "Keine Objektinformationen verfügbar",
|
||||
"search_page_no_places": "Keine Informationen über Orte verfügbar",
|
||||
"search_page_places": "Orte",
|
||||
"search_page_recently_added": "Recently added",
|
||||
"search_page_screenshots": "Screenshots",
|
||||
"search_page_selfies": "Selfies",
|
||||
"search_page_things": "Dinge",
|
||||
"search_page_videos": "Videos",
|
||||
"search_page_view_all_button": "View all",
|
||||
"search_page_your_activity": "Your activity",
|
||||
"search_result_page_new_search_hint": "Neue Suche",
|
||||
"search_suggestion_list_smart_search_hint_1": "Smart search is enabled by default, to search for metadata use the syntax ",
|
||||
"search_suggestion_list_smart_search_hint_2": "m:your-search-term",
|
||||
"select_additional_user_for_sharing_page_suggestions": "Vorschläge",
|
||||
"select_user_for_sharing_page_err_album": "Album konnte nicht erstellt werden",
|
||||
"select_user_for_sharing_page_share_suggestions": "Suggestions",
|
||||
"server_info_box_app_version": "App Version",
|
||||
"server_info_box_server_version": "Server Version",
|
||||
"setting_image_viewer_help": "The detail viewer loads the small thumbnail first, then loads the medium-size preview (if enabled), finally loads the original (if enabled).",
|
||||
"setting_image_viewer_original_subtitle": "Enable to load the original full-resolution image (large!). Disable to reduce data usage (both network and on device cache).",
|
||||
"setting_image_viewer_original_title": "Load original image",
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
{
|
||||
"add_to_album_bottom_sheet_added": "Added to {album}",
|
||||
"add_to_album_bottom_sheet_already_exists": "Already in {album}",
|
||||
"album_info_card_backup_album_excluded": "EXCLUDED",
|
||||
"album_info_card_backup_album_included": "INCLUDED",
|
||||
"album_thumbnail_card_item": "1 item",
|
||||
"album_thumbnail_card_items": "{} items",
|
||||
"album_thumbnail_card_shared": " · Shared",
|
||||
"album_thumbnail_owned": "Owned",
|
||||
"album_thumbnail_shared_by": "Shared by {}",
|
||||
"album_viewer_appbar_share_delete": "Delete album",
|
||||
"album_viewer_appbar_share_err_delete": "Failed to delete album",
|
||||
"album_viewer_appbar_share_err_leave": "Failed to leave album",
|
||||
@@ -12,10 +16,11 @@
|
||||
"album_viewer_appbar_share_leave": "Leave album",
|
||||
"album_viewer_appbar_share_remove": "Remove from album",
|
||||
"album_viewer_page_share_add_users": "Add users",
|
||||
"all_videos_page_title": "Videos",
|
||||
"asset_list_layout_settings_dynamic_layout_title": "Dynamic layout",
|
||||
"asset_list_layout_settings_group_by": "Group assets by",
|
||||
"asset_list_layout_settings_group_by_month_day": "Month + day",
|
||||
"asset_list_layout_settings_group_by_month": "Month",
|
||||
"asset_list_layout_settings_group_by_month_day": "Month + day",
|
||||
"asset_list_settings_subtitle": "Photo grid layout settings",
|
||||
"asset_list_settings_title": "Photo Grid",
|
||||
"backup_album_selection_page_albums_device": "Albums on device ({})",
|
||||
@@ -33,6 +38,9 @@
|
||||
"backup_background_service_in_progress_notification": "Backing up your assets…",
|
||||
"backup_background_service_upload_failure_notification": "Failed to upload {}",
|
||||
"backup_controller_page_albums": "Backup Albums",
|
||||
"backup_controller_page_background_app_refresh_disabled_content": "Enable background app refresh in Settings > General > Background App Refresh in order to use background backup.",
|
||||
"backup_controller_page_background_app_refresh_disabled_title": "Background app refresh disabled",
|
||||
"backup_controller_page_background_app_refresh_enable_button_text": "Go to settings",
|
||||
"backup_controller_page_background_battery_info_link": "Show me how",
|
||||
"backup_controller_page_background_battery_info_message": "For the best background backup experience, please disable any battery optimizations restricting background activity for Immich.\n\nSince this is device-specific, please lookup the required information for your device manufacturer.",
|
||||
"backup_controller_page_background_battery_info_ok": "OK",
|
||||
@@ -87,17 +95,31 @@
|
||||
"cache_settings_subtitle": "Control the caching behaviour of the Immich mobile application",
|
||||
"cache_settings_thumbnail_size": "Thumbnail cache size ({} assets)",
|
||||
"cache_settings_title": "Caching Settings",
|
||||
"change_password_form_confirm_password": "Confirm Password",
|
||||
"change_password_form_description": "Hi {firstName} {lastName},\n\nThis is either the first time you are signing into the system or a request has been made to change your password. Please enter the new password below.",
|
||||
"change_password_form_new_password": "New Password",
|
||||
"change_password_form_password_mismatch": "Passwords do not match",
|
||||
"change_password_form_reenter_new_password": "Re-enter New Password",
|
||||
"common_add_to_album": "Add to album",
|
||||
"common_change_password": "Change Password",
|
||||
"common_create_new_album": "Create new album",
|
||||
"common_server_error": "Please check your network connection, make sure the server is reachable and app/server versions are compatible.",
|
||||
"common_shared": "Shared",
|
||||
"control_bottom_app_bar_add_to_album": "Add to album",
|
||||
"control_bottom_app_bar_album_info": "{} items",
|
||||
"control_bottom_app_bar_album_info_shared": "{} items · Shared",
|
||||
"control_bottom_app_bar_create_new_album": "Create new album",
|
||||
"control_bottom_app_bar_delete": "Delete",
|
||||
"control_bottom_app_bar_favorite": "Favorite",
|
||||
"control_bottom_app_bar_archive": "Archive",
|
||||
"control_bottom_app_bar_share": "Share",
|
||||
"create_album_page_untitled": "Untitled",
|
||||
"create_shared_album_page_create": "Create",
|
||||
"create_shared_album_page_share": "Share",
|
||||
"create_shared_album_page_share_add_assets": "ADD ASSETS",
|
||||
"create_shared_album_page_share_select_photos": "Select Photos",
|
||||
"curated_location_page_title": "Places",
|
||||
"curated_object_page_title": "Things",
|
||||
"daily_title_text_date": "E, MMM dd",
|
||||
"daily_title_text_date_year": "E, MMM dd, yyyy",
|
||||
"date_format": "E, LLL d, y • h:mm a",
|
||||
@@ -114,15 +136,23 @@
|
||||
"experimental_settings_title": "Experimental",
|
||||
"favorites_page_title": "Favorites",
|
||||
"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_success": "Added {added} assets to album {album}.",
|
||||
"home_page_building_timeline": "Building the timeline",
|
||||
"home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
|
||||
"home_page_archive_err_local": "Can not archive local assets yet, skipping",
|
||||
"home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s).",
|
||||
"image_viewer_page_state_provider_download_error": "Download Error",
|
||||
"image_viewer_page_state_provider_download_success": "Download Success",
|
||||
"library_page_albums": "Albums",
|
||||
"library_page_device_albums": "Albums on Device",
|
||||
"library_page_favorites": "Favorites",
|
||||
"library_page_new_album": "New album",
|
||||
"library_page_sharing": "Sharing",
|
||||
"library_page_archive": "Archive",
|
||||
"library_page_sort_created": "Most recently created",
|
||||
"library_page_sort_title": "Album title",
|
||||
"login_form_api_exception": "API exception. Please check the server URL and try again.",
|
||||
"login_form_button_text": "Login",
|
||||
"login_form_email_hint": "youremail@email.com",
|
||||
"login_form_endpoint_hint": "http://your-server-ip:port/api",
|
||||
@@ -137,22 +167,55 @@
|
||||
"login_form_failed_login": "Error logging you in, check server URL, email and password",
|
||||
"login_form_label_email": "Email",
|
||||
"login_form_label_password": "Password",
|
||||
"login_form_next_button": "Next",
|
||||
"login_form_password_hint": "password",
|
||||
"login_form_save_login": "Stay logged in",
|
||||
"login_form_server_empty": "Enter a server URL.",
|
||||
"login_form_server_error": "Could not connect to server.",
|
||||
"monthly_title_text_date_format": "MMMM y",
|
||||
"motion_photos_page_title": "Motion Photos",
|
||||
"notification_permission_dialog_cancel": "Cancel",
|
||||
"notification_permission_dialog_content": "To enable notifications, go to Settings and select allow.",
|
||||
"notification_permission_dialog_settings": "Settings",
|
||||
"notification_permission_list_tile_content": "Grant permission to enable notifications.",
|
||||
"notification_permission_list_tile_enable_button": "Enable Notifications",
|
||||
"notification_permission_list_tile_title": "Notification Permission",
|
||||
"permission_onboarding_continue_anyway": "Continue anyway",
|
||||
"permission_onboarding_get_started": "Get started",
|
||||
"permission_onboarding_go_to_settings": "Go to settings",
|
||||
"permission_onboarding_grant_permission": "Grant permission",
|
||||
"permission_onboarding_log_out": "Log out",
|
||||
"permission_onboarding_permission_denied": "Permission denied. To use Immich, grant photo and video permissions in Settings.",
|
||||
"permission_onboarding_permission_granted": "Permission granted! You are all set.",
|
||||
"permission_onboarding_permission_limited": "Permission limited. To let Immich backup and manage your entire gallery collection, grant photo and video permissions in Settings.",
|
||||
"permission_onboarding_request": "Immich requires permission to view your photos and videos.",
|
||||
"profile_drawer_app_logs": "Logs",
|
||||
"profile_drawer_client_server_up_to_date": "Client and Server are up-to-date",
|
||||
"profile_drawer_settings": "Settings",
|
||||
"profile_drawer_sign_out": "Sign Out",
|
||||
"recently_added_page_title": "Recently Added",
|
||||
"search_bar_hint": "Search your photos",
|
||||
"search_page_categories": "Categories",
|
||||
"search_page_favorites": "Favorites",
|
||||
"search_page_motion_photos": "Motion Photos",
|
||||
"search_page_no_objects": "No Objects Info Available",
|
||||
"search_page_no_places": "No Places Info Available",
|
||||
"search_page_places": "Places",
|
||||
"search_page_recently_added": "Recently added",
|
||||
"search_page_screenshots": "Screenshots",
|
||||
"search_page_selfies": "Selfies",
|
||||
"search_page_things": "Things",
|
||||
"search_page_videos": "Videos",
|
||||
"search_page_view_all_button": "View all",
|
||||
"search_page_your_activity": "Your activity",
|
||||
"search_result_page_new_search_hint": "New Search",
|
||||
"search_suggestion_list_smart_search_hint_1": "Smart search is enabled by default, to search for metadata use the syntax ",
|
||||
"search_suggestion_list_smart_search_hint_2": "m:your-search-term",
|
||||
"select_additional_user_for_sharing_page_suggestions": "Suggestions",
|
||||
"select_user_for_sharing_page_err_album": "Failed to create album",
|
||||
"select_user_for_sharing_page_share_suggestions": "Suggestions",
|
||||
"server_info_box_app_version": "App Version",
|
||||
"server_info_box_server_version": "Server Version",
|
||||
"setting_image_viewer_help": "The detail viewer loads the small thumbnail first, then loads the medium-size preview (if enabled), finally loads the original (if enabled).",
|
||||
"setting_image_viewer_original_subtitle": "Enable to load the original full-resolution image (large!). Disable to reduce data usage (both network and on device cache).",
|
||||
"setting_image_viewer_original_title": "Load original image",
|
||||
@@ -202,5 +265,12 @@
|
||||
"version_announcement_overlay_text_1": "Hi friend, there is a new release of",
|
||||
"version_announcement_overlay_text_2": "please take your time to visit the ",
|
||||
"version_announcement_overlay_text_3": " and ensure your docker-compose and .env setup is up-to-date to prevent any misconfigurations, especially if you use WatchTower or any mechanism that handles updating your server application automatically.",
|
||||
"version_announcement_overlay_title": "New Server Version Available \uD83C\uDF89"
|
||||
"version_announcement_overlay_title": "New Server Version Available \uD83C\uDF89",
|
||||
"advanced_settings_tile_title": "Advanced",
|
||||
"advanced_settings_tile_subtitle": "Advanced user's settings",
|
||||
"advanced_settings_troubleshooting_title": "Troubleshooting",
|
||||
"advanced_settings_troubleshooting_subtitle": "Enable additional features for troubleshooting",
|
||||
"description_input_submit_error": "Error updating description, check the log for more details",
|
||||
"description_input_hint_text": "Add description...",
|
||||
"archive_page_title": "Archive ({})"
|
||||
}
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
{
|
||||
"add_to_album_bottom_sheet_added": "Added to {album}",
|
||||
"add_to_album_bottom_sheet_already_exists": "Already in {album}",
|
||||
"album_info_card_backup_album_excluded": "EXCLUIDOS",
|
||||
"album_info_card_backup_album_included": "INCLUIDOS",
|
||||
"album_thumbnail_card_item": "1 item",
|
||||
"album_thumbnail_card_items": "{} items",
|
||||
"album_thumbnail_card_shared": " · Shared",
|
||||
"album_thumbnail_owned": "Owned",
|
||||
"album_thumbnail_shared_by": "Shared by {}",
|
||||
"album_viewer_appbar_share_delete": "Eliminar álbum ",
|
||||
"album_viewer_appbar_share_err_delete": "No ha podido eliminar el álbum",
|
||||
"album_viewer_appbar_share_err_leave": "No ha podido dejar el álbum",
|
||||
@@ -12,6 +16,11 @@
|
||||
"album_viewer_appbar_share_leave": "Abandonar álbum ",
|
||||
"album_viewer_appbar_share_remove": "Eliminar del álbum ",
|
||||
"album_viewer_page_share_add_users": "Añadir usuarios",
|
||||
"all_videos_page_title": "Videos",
|
||||
"asset_list_layout_settings_dynamic_layout_title": "Disposición dinámica",
|
||||
"asset_list_layout_settings_group_by": "Agrupar recursos por",
|
||||
"asset_list_layout_settings_group_by_month": "Mes",
|
||||
"asset_list_layout_settings_group_by_month_day": "Mes + día",
|
||||
"asset_list_settings_subtitle": "Photo grid layout settings",
|
||||
"asset_list_settings_title": "Photo Grid",
|
||||
"backup_album_selection_page_albums_device": "Álbumes en el dispositivo ({})",
|
||||
@@ -29,6 +38,9 @@
|
||||
"backup_background_service_in_progress_notification": "Backing up your assets…",
|
||||
"backup_background_service_upload_failure_notification": "Failed to upload {}",
|
||||
"backup_controller_page_albums": "Álbumes de copia de seguridad",
|
||||
"backup_controller_page_background_app_refresh_disabled_content": "Enable background app refresh in Settings > General > Background App Refresh in order to use background backup.",
|
||||
"backup_controller_page_background_app_refresh_disabled_title": "Background app refresh disabled",
|
||||
"backup_controller_page_background_app_refresh_enable_button_text": "Go to settings",
|
||||
"backup_controller_page_background_battery_info_link": "Show me how",
|
||||
"backup_controller_page_background_battery_info_message": "For the best background backup experience, please disable any battery optimizations restricting background activity for Immich.\n\nSince this is device-specific, please lookup the required information for your device manufacturer.",
|
||||
"backup_controller_page_background_battery_info_ok": "OK",
|
||||
@@ -83,17 +95,30 @@
|
||||
"cache_settings_subtitle": "Control the caching behaviour of the Immich mobile application",
|
||||
"cache_settings_thumbnail_size": "Thumbnail cache size ({} assets)",
|
||||
"cache_settings_title": "Caching Settings",
|
||||
"change_password_form_confirm_password": "Confirm Password",
|
||||
"change_password_form_description": "Hi {firstName} {lastName},\n\nThis is either the first time you are signing into the system or a request has been made to change your password. Please enter the new password below.",
|
||||
"change_password_form_new_password": "New Password",
|
||||
"change_password_form_password_mismatch": "Passwords do not match",
|
||||
"change_password_form_reenter_new_password": "Re-enter New Password",
|
||||
"common_add_to_album": "Add to album",
|
||||
"common_change_password": "Change Password",
|
||||
"common_create_new_album": "Create new album",
|
||||
"common_server_error": "Please check your network connection, make sure the server is reachable and app/server versions are compatible.",
|
||||
"common_shared": "Shared",
|
||||
"control_bottom_app_bar_add_to_album": "Añadir al álbum",
|
||||
"control_bottom_app_bar_album_info": "{} elementos",
|
||||
"control_bottom_app_bar_album_info_shared": "{} elementos · Compartido",
|
||||
"control_bottom_app_bar_create_new_album": "Crear nuevo álbum",
|
||||
"control_bottom_app_bar_delete": "Eliminar",
|
||||
"control_bottom_app_bar_favorite": "Favorite",
|
||||
"control_bottom_app_bar_share": "Share",
|
||||
"create_album_page_untitled": "Untitled",
|
||||
"create_shared_album_page_create": "Create",
|
||||
"create_shared_album_page_share": "Compartir",
|
||||
"create_shared_album_page_share_add_assets": "AÑADIR ACTIVOS",
|
||||
"create_shared_album_page_share_select_photos": "Seleccionar Fotos",
|
||||
"curated_location_page_title": "Places",
|
||||
"curated_object_page_title": "Things",
|
||||
"daily_title_text_date": "E dd, MMM",
|
||||
"daily_title_text_date_year": "E dd de MMM, yyyy",
|
||||
"date_format": "E d, LLL y • h:mm a",
|
||||
@@ -108,24 +133,30 @@
|
||||
"experimental_settings_new_asset_list_title": "Enable experimental photo grid",
|
||||
"experimental_settings_subtitle": "Use at your own risk!",
|
||||
"experimental_settings_title": "Experimental",
|
||||
"favorites_page_title": "Favorites",
|
||||
"favorites_page_title": "Favoritos",
|
||||
"home_page_add_to_album_conflicts": "Añadidos {added} elementos al álbum {album}. {failed} elementos ya están añadidos.",
|
||||
"home_page_add_to_album_err_local": "Can not add local assets to albums yet, skipping",
|
||||
"home_page_add_to_album_success": "Añadidos {added} elementos al álbum {album}.",
|
||||
"home_page_building_timeline": "Building the timeline",
|
||||
"home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s).",
|
||||
"home_page_building_timeline": "Construyendo la línea de tiempo",
|
||||
"home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
|
||||
"home_page_first_time_notice": "Si esta es la primera vez que usas la app, por favor, asegúrate de elegir un álbum de respaldo para que la línea de tiempo pueda cargar fotos y videos en los álbumes.",
|
||||
"image_viewer_page_state_provider_download_error": "Download Error",
|
||||
"image_viewer_page_state_provider_download_success": "Download Success",
|
||||
"library_page_albums": "Albums",
|
||||
"library_page_favorites": "Favorites",
|
||||
"library_page_device_albums": "Albums on Device",
|
||||
"library_page_favorites": "Favoritos",
|
||||
"library_page_new_album": "New album",
|
||||
"library_page_sharing": "Sharing",
|
||||
"library_page_sort_created": "Most recently created",
|
||||
"library_page_sort_title": "Album title",
|
||||
"library_page_sharing": "Compartiendo",
|
||||
"library_page_sort_created": "Creado más recientemente",
|
||||
"library_page_sort_title": "Título del álbum",
|
||||
"login_form_api_exception": "API exception. Please check the server URL and try again.",
|
||||
"login_form_button_text": "Iniciar Sesión",
|
||||
"login_form_email_hint": "tucorreo@correo.com",
|
||||
"login_form_endpoint_hint": "http://tu-ip-de-servidor:puerto/api",
|
||||
"login_form_endpoint_url": "URL del servidor",
|
||||
"login_form_err_http": "Por favor, especifique http:// o https://",
|
||||
"login_form_err_invalid_email": "Correo electrónico no válido",
|
||||
"login_form_err_invalid_url": "Invalid URL",
|
||||
"login_form_err_invalid_url": "URL no válida",
|
||||
"login_form_err_leading_whitespace": "Espacio en blanco inicial",
|
||||
"login_form_err_trailing_whitespace": "Espacio en blanco al final",
|
||||
"login_form_failed_get_oauth_server_config": "Error logging using OAuth, check server URL",
|
||||
@@ -133,22 +164,55 @@
|
||||
"login_form_failed_login": "Error logging you in, check server URL, email and password",
|
||||
"login_form_label_email": "Correo",
|
||||
"login_form_label_password": "Contraseña",
|
||||
"login_form_next_button": "Next",
|
||||
"login_form_password_hint": "contraseña",
|
||||
"login_form_save_login": "Mantener la sesión iniciada",
|
||||
"login_form_server_empty": "Enter a server URL.",
|
||||
"login_form_server_error": "Could not connect to server.",
|
||||
"monthly_title_text_date_format": "MMMM y",
|
||||
"motion_photos_page_title": "Motion Photos",
|
||||
"notification_permission_dialog_cancel": "Cancel",
|
||||
"notification_permission_dialog_content": "To enable notifications, go to Settings and select allow.",
|
||||
"notification_permission_dialog_settings": "Settings",
|
||||
"notification_permission_list_tile_content": "Grant permission to enable notifications.",
|
||||
"notification_permission_list_tile_enable_button": "Enable Notifications",
|
||||
"notification_permission_list_tile_title": "Notification Permission",
|
||||
"permission_onboarding_continue_anyway": "Continue anyway",
|
||||
"permission_onboarding_get_started": "Get started",
|
||||
"permission_onboarding_go_to_settings": "Go to settings",
|
||||
"permission_onboarding_grant_permission": "Grant permission",
|
||||
"permission_onboarding_log_out": "Log out",
|
||||
"permission_onboarding_permission_denied": "Permission denied. To use Immich, grant photo and video permissions in Settings.",
|
||||
"permission_onboarding_permission_granted": "Permission granted! You are all set.",
|
||||
"permission_onboarding_permission_limited": "Permission limited. To let Immich backup and manage your entire gallery collection, grant photo and video permissions in Settings.",
|
||||
"permission_onboarding_request": "Immich requires permission to view your photos and videos.",
|
||||
"profile_drawer_app_logs": "Logs",
|
||||
"profile_drawer_client_server_up_to_date": "El Cliente y el Servidor están actualizados",
|
||||
"profile_drawer_settings": "Settings",
|
||||
"profile_drawer_sign_out": "Cerrar Sesión",
|
||||
"recently_added_page_title": "Recently Added",
|
||||
"search_bar_hint": "Busca tus fotos",
|
||||
"search_page_categories": "Categories",
|
||||
"search_page_favorites": "Favorites",
|
||||
"search_page_motion_photos": "Motion Photos",
|
||||
"search_page_no_objects": "No Objects Info Available",
|
||||
"search_page_no_places": "No hay información de lugares disponibles",
|
||||
"search_page_places": "Lugares",
|
||||
"search_page_recently_added": "Recently added",
|
||||
"search_page_screenshots": "Screenshots",
|
||||
"search_page_selfies": "Selfies",
|
||||
"search_page_things": "Cosas",
|
||||
"search_page_videos": "Videos",
|
||||
"search_page_view_all_button": "View all",
|
||||
"search_page_your_activity": "Your activity",
|
||||
"search_result_page_new_search_hint": "Nueva Busqueda",
|
||||
"search_suggestion_list_smart_search_hint_1": "Smart search is enabled by default, to search for metadata use the syntax ",
|
||||
"search_suggestion_list_smart_search_hint_2": "m:your-search-term",
|
||||
"select_additional_user_for_sharing_page_suggestions": "Sugerencias",
|
||||
"select_user_for_sharing_page_err_album": "Fallo al crear el álbum",
|
||||
"select_user_for_sharing_page_share_suggestions": "Suggestions",
|
||||
"server_info_box_app_version": "App Version",
|
||||
"server_info_box_server_version": "Server Version",
|
||||
"setting_image_viewer_help": "The detail viewer loads the small thumbnail first, then loads the medium-size preview (if enabled), finally loads the original (if enabled).",
|
||||
"setting_image_viewer_original_subtitle": "Habilitar para cargar la imagen en resolución original (¡muy grande!). Deshabilitar para reducir el consumo de datos (de red y caché).",
|
||||
"setting_image_viewer_original_title": "Cargar imagen original",
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
{
|
||||
"add_to_album_bottom_sheet_added": "Added to {album}",
|
||||
"add_to_album_bottom_sheet_already_exists": "Already in {album}",
|
||||
"album_info_card_backup_album_excluded": "JÄTETTY POIS",
|
||||
"album_info_card_backup_album_included": "SISÄLLYTETTY",
|
||||
"album_thumbnail_card_item": "1 kohde",
|
||||
"album_thumbnail_card_items": "{} kohdetta",
|
||||
"album_thumbnail_card_shared": "Jaettu",
|
||||
"album_thumbnail_owned": "Owned",
|
||||
"album_thumbnail_shared_by": "Shared by {}",
|
||||
"album_viewer_appbar_share_delete": "Poista albumi",
|
||||
"album_viewer_appbar_share_err_delete": "Albumin poistaminen epäonnistui",
|
||||
"album_viewer_appbar_share_err_leave": "Albumista poistuminen epäonnistui",
|
||||
@@ -12,6 +16,11 @@
|
||||
"album_viewer_appbar_share_leave": "Poistu albumista",
|
||||
"album_viewer_appbar_share_remove": "Poista albumista",
|
||||
"album_viewer_page_share_add_users": "Lisää käyttäjiä",
|
||||
"all_videos_page_title": "Videos",
|
||||
"asset_list_layout_settings_dynamic_layout_title": "Dynaaminen asetelma",
|
||||
"asset_list_layout_settings_group_by": "Ryhmittele",
|
||||
"asset_list_layout_settings_group_by_month": "Kuukauden mukaan",
|
||||
"asset_list_layout_settings_group_by_month_day": "Kuukauden ja päivän mukaan",
|
||||
"asset_list_settings_subtitle": "Kuvaruudukon asettelu",
|
||||
"asset_list_settings_title": "Kuvaruudukko",
|
||||
"backup_album_selection_page_albums_device": "Laitteen albumit ({})",
|
||||
@@ -29,6 +38,9 @@
|
||||
"backup_background_service_in_progress_notification": "Varmuuskopioidaan kohteita...",
|
||||
"backup_background_service_upload_failure_notification": "Lähetys palvelimelle epäonnistui {}",
|
||||
"backup_controller_page_albums": "Varmuuskopioi albumit",
|
||||
"backup_controller_page_background_app_refresh_disabled_content": "Enable background app refresh in Settings > General > Background App Refresh in order to use background backup.",
|
||||
"backup_controller_page_background_app_refresh_disabled_title": "Background app refresh disabled",
|
||||
"backup_controller_page_background_app_refresh_enable_button_text": "Go to settings",
|
||||
"backup_controller_page_background_battery_info_link": "Näytä minulle miten",
|
||||
"backup_controller_page_background_battery_info_message": "Kytke pois päältä kaikki Immichin taustatyöskentelyyn liittyvät akun optimoinnit, jotta varmistat taustavarmuuskopioinnin parhaan mahdollisen toiminnan.\n\nKoska tämä on laitekohtaista, tarkista tarvittavat toimet laitevalmistajan ohjeista.",
|
||||
"backup_controller_page_background_battery_info_ok": "OK",
|
||||
@@ -83,17 +95,30 @@
|
||||
"cache_settings_subtitle": "Hallitse Immich-mobiilisovelluksen välimuistin käyttöä",
|
||||
"cache_settings_thumbnail_size": "Esikatselukuvien välimuistin koko ({} kohdetta)",
|
||||
"cache_settings_title": "Välimuistin asetukset",
|
||||
"change_password_form_confirm_password": "Confirm Password",
|
||||
"change_password_form_description": "Hi {firstName} {lastName},\n\nThis is either the first time you are signing into the system or a request has been made to change your password. Please enter the new password below.",
|
||||
"change_password_form_new_password": "New Password",
|
||||
"change_password_form_password_mismatch": "Passwords do not match",
|
||||
"change_password_form_reenter_new_password": "Re-enter New Password",
|
||||
"common_add_to_album": "Add to album",
|
||||
"common_change_password": "Change Password",
|
||||
"common_create_new_album": "Create new album",
|
||||
"common_server_error": "Please check your network connection, make sure the server is reachable and app/server versions are compatible.",
|
||||
"common_shared": "Shared",
|
||||
"control_bottom_app_bar_add_to_album": "Lisää albumiin",
|
||||
"control_bottom_app_bar_album_info": "{} kohdetta",
|
||||
"control_bottom_app_bar_album_info_shared": "{} kohdetta · Jaettu",
|
||||
"control_bottom_app_bar_create_new_album": "Luo uusi albumi",
|
||||
"control_bottom_app_bar_delete": "Poista",
|
||||
"control_bottom_app_bar_favorite": "Favorite",
|
||||
"control_bottom_app_bar_share": "Jaa",
|
||||
"create_album_page_untitled": "Nimetön",
|
||||
"create_shared_album_page_create": "Luo",
|
||||
"create_shared_album_page_share": "Jaa",
|
||||
"create_shared_album_page_share_add_assets": "LISÄÄ KOHTEITA",
|
||||
"create_shared_album_page_share_select_photos": "Valitse kuvat",
|
||||
"curated_location_page_title": "Places",
|
||||
"curated_object_page_title": "Things",
|
||||
"daily_title_text_date": "E, MMM dd",
|
||||
"daily_title_text_date_year": "E, MMM dd, yyyy",
|
||||
"date_format": "E, LLL d, y • h:mm a",
|
||||
@@ -108,24 +133,30 @@
|
||||
"experimental_settings_new_asset_list_title": "Ota käyttöön kokeellinen kuvaruudukko",
|
||||
"experimental_settings_subtitle": "Käyttö omalla vastuulla!",
|
||||
"experimental_settings_title": "Kokeellinen",
|
||||
"favorites_page_title": "Favorites",
|
||||
"favorites_page_title": "Suosikit",
|
||||
"home_page_add_to_album_conflicts": "Lisätty {added} kohdetta albumiin {album}. {failed} kohdetta on jo albumissa.",
|
||||
"home_page_add_to_album_err_local": "Can not add local assets to albums yet, skipping",
|
||||
"home_page_add_to_album_success": "Lisätty {added} kohdetta albumiin {album}.",
|
||||
"home_page_building_timeline": "Building the timeline",
|
||||
"home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s).",
|
||||
"home_page_building_timeline": "Rakennetaan aikajanaa",
|
||||
"home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
|
||||
"home_page_first_time_notice": "Jos käytät sovellusta ensimmäistä kertaa, muista valita varmuuskopioitavat albumi(t), jotta aikajanalla voi olla kuvia ja videoita.",
|
||||
"image_viewer_page_state_provider_download_error": "Download Error",
|
||||
"image_viewer_page_state_provider_download_success": "Download Success",
|
||||
"library_page_albums": "Albumit",
|
||||
"library_page_favorites": "Favorites",
|
||||
"library_page_device_albums": "Albums on Device",
|
||||
"library_page_favorites": "Suosikit",
|
||||
"library_page_new_album": "Uusi albumi",
|
||||
"library_page_sharing": "Sharing",
|
||||
"library_page_sort_created": "Most recently created",
|
||||
"library_page_sort_title": "Album title",
|
||||
"library_page_sharing": "Jakaminen",
|
||||
"library_page_sort_created": "Viimeisin luotu",
|
||||
"library_page_sort_title": "Albumin otsikko",
|
||||
"login_form_api_exception": "API exception. Please check the server URL and try again.",
|
||||
"login_form_button_text": "Kirjaudu",
|
||||
"login_form_email_hint": "sahkopostisi@esimerkki.fi",
|
||||
"login_form_endpoint_hint": "http://palvelimesi-osoite:portti/api",
|
||||
"login_form_endpoint_url": "Palvelimen URL",
|
||||
"login_form_err_http": "Lisää http:// tai https://",
|
||||
"login_form_err_invalid_email": "Virheellinen sähköpostiosoite",
|
||||
"login_form_err_invalid_url": "Invalid URL",
|
||||
"login_form_err_invalid_url": "Virheellinen URL",
|
||||
"login_form_err_leading_whitespace": "Alussa välilyönti",
|
||||
"login_form_err_trailing_whitespace": "Lopussa välilyönti",
|
||||
"login_form_failed_get_oauth_server_config": "Virhe kirjauduttaessa OAuth:lla, tarkista palvelimen URL",
|
||||
@@ -133,22 +164,55 @@
|
||||
"login_form_failed_login": "Virhe kirjautumisessa. Tarkista palvelimen URL, sähköpostiosoite ja salasana.",
|
||||
"login_form_label_email": "Sähköposti",
|
||||
"login_form_label_password": "Salasana",
|
||||
"login_form_next_button": "Next",
|
||||
"login_form_password_hint": "salasana",
|
||||
"login_form_save_login": "Pysy kirjautuneena",
|
||||
"login_form_server_empty": "Enter a server URL.",
|
||||
"login_form_server_error": "Could not connect to server.",
|
||||
"monthly_title_text_date_format": "MMMM y",
|
||||
"motion_photos_page_title": "Motion Photos",
|
||||
"notification_permission_dialog_cancel": "Cancel",
|
||||
"notification_permission_dialog_content": "To enable notifications, go to Settings and select allow.",
|
||||
"notification_permission_dialog_settings": "Settings",
|
||||
"notification_permission_list_tile_content": "Grant permission to enable notifications.",
|
||||
"notification_permission_list_tile_enable_button": "Enable Notifications",
|
||||
"notification_permission_list_tile_title": "Notification Permission",
|
||||
"permission_onboarding_continue_anyway": "Continue anyway",
|
||||
"permission_onboarding_get_started": "Get started",
|
||||
"permission_onboarding_go_to_settings": "Go to settings",
|
||||
"permission_onboarding_grant_permission": "Grant permission",
|
||||
"permission_onboarding_log_out": "Log out",
|
||||
"permission_onboarding_permission_denied": "Permission denied. To use Immich, grant photo and video permissions in Settings.",
|
||||
"permission_onboarding_permission_granted": "Permission granted! You are all set.",
|
||||
"permission_onboarding_permission_limited": "Permission limited. To let Immich backup and manage your entire gallery collection, grant photo and video permissions in Settings.",
|
||||
"permission_onboarding_request": "Immich requires permission to view your photos and videos.",
|
||||
"profile_drawer_app_logs": "Lokit",
|
||||
"profile_drawer_client_server_up_to_date": "Asiakassovellus ja palvelin ovat ajan tasalla",
|
||||
"profile_drawer_settings": "Asetukset",
|
||||
"profile_drawer_sign_out": "Kirjaudu ulos",
|
||||
"recently_added_page_title": "Recently Added",
|
||||
"search_bar_hint": "Etsi kuvia",
|
||||
"search_page_categories": "Categories",
|
||||
"search_page_favorites": "Favorites",
|
||||
"search_page_motion_photos": "Motion Photos",
|
||||
"search_page_no_objects": "Objektitietoja ei ole saatavilla",
|
||||
"search_page_no_places": "Paikkatietoja ei ole saatavilla",
|
||||
"search_page_places": "Paikat",
|
||||
"search_page_recently_added": "Recently added",
|
||||
"search_page_screenshots": "Screenshots",
|
||||
"search_page_selfies": "Selfies",
|
||||
"search_page_things": "Asiat",
|
||||
"search_page_videos": "Videos",
|
||||
"search_page_view_all_button": "View all",
|
||||
"search_page_your_activity": "Your activity",
|
||||
"search_result_page_new_search_hint": "Uusi haku",
|
||||
"search_suggestion_list_smart_search_hint_1": "Smart search is enabled by default, to search for metadata use the syntax ",
|
||||
"search_suggestion_list_smart_search_hint_2": "m:your-search-term",
|
||||
"select_additional_user_for_sharing_page_suggestions": "Ehdotukset",
|
||||
"select_user_for_sharing_page_err_album": "Albumin luonti epäonnistui",
|
||||
"select_user_for_sharing_page_share_suggestions": "Ehdotukset",
|
||||
"server_info_box_app_version": "App Version",
|
||||
"server_info_box_server_version": "Server Version",
|
||||
"setting_image_viewer_help": "Sovellus lataa ensin pienen esikatselukuvan, toisena keskitarkkuuksisen kuvan (jos käytössä) ja kolmantena alkuperäisen täysitarkkuuksisen kuvan (jos käytössä)",
|
||||
"setting_image_viewer_original_subtitle": "Ota käyttöön ladataksesi alkuperäinen täysitarkkuuksinen kuva (suuri!). Poista käytöstä vähentääksesi datan käyttöä (sekä verkossa että laitteen välimuistissa).",
|
||||
"setting_image_viewer_original_title": "Lataa alkuperäinen kuva",
|
||||
|
||||