Compare commits
440 Commits
v1.41.1_64
...
v1.52.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
b37162099e | ||
|
|
dab74662e9 | ||
|
|
3d103046bc | ||
|
|
3ca62d9c55 | ||
|
|
2cd45ed1de | ||
|
|
263598f2cf | ||
|
|
1d1d71c779 | ||
|
|
fd13265131 | ||
|
|
911c35a7f1 | ||
|
|
adb265794c | ||
|
|
8c20d8cb3d | ||
|
|
43359f1d26 | ||
|
|
dc9da7480c | ||
|
|
18647203cc | ||
|
|
be8f2c01a2 | ||
|
|
c8fffe4ade | ||
|
|
43fd7737f1 | ||
|
|
fb4969d5d1 | ||
|
|
3cc4af5947 | ||
|
|
ac39ebddc0 | ||
|
|
29bb1f7ef2 | ||
|
|
b8d2f5b373 | ||
|
|
2139853dd9 | ||
|
|
527aa61a87 | ||
|
|
4261fc8a04 | ||
|
|
7dbddba757 | ||
|
|
16183791f3 | ||
|
|
f38c7a4b7e | ||
|
|
bb0b2a1f53 | ||
|
|
0048662182 | ||
|
|
7bd2455175 | ||
|
|
43e49f36b7 | ||
|
|
e4b3479779 | ||
|
|
6bac9c7e8f | ||
|
|
ff3cde4dfb | ||
|
|
7aab84f2d9 | ||
|
|
3a940711eb | ||
|
|
2b0b2bb1ae | ||
|
|
e39507552f | ||
|
|
b019ab79f9 | ||
|
|
43da8c2a72 | ||
|
|
0b65cea6fd | ||
|
|
a1806390b0 | ||
|
|
5d6559e839 | ||
|
|
29c79ad1d8 | ||
|
|
d77a1aba7a | ||
|
|
9e21b16553 | ||
|
|
dcb56ae775 | ||
|
|
ab2c019a7a | ||
|
|
eb408d4858 | ||
|
|
4f38851880 | ||
|
|
2c356ec87f | ||
|
|
bb84464216 | ||
|
|
32b9e0bad4 | ||
|
|
02f5a86ee9 | ||
|
|
391bf052e4 | ||
|
|
d2a9363fc5 | ||
|
|
68af4cd5ba | ||
|
|
c82dcb11e1 | ||
|
|
d0f8d8d1f9 | ||
|
|
6a852332de | ||
|
|
830fec0c29 | ||
|
|
aa68d35f42 | ||
|
|
6e6fe9bc87 | ||
|
|
29f68e6dbb | ||
|
|
9428b2576b | ||
|
|
3210302ecd | ||
|
|
f23979024a | ||
|
|
870a65fa6d | ||
|
|
199eb20b66 | ||
|
|
91114e5aa0 | ||
|
|
dfbc831525 | ||
|
|
1a640609c7 | ||
|
|
00630bd4a3 | ||
|
|
fb408d7aa3 | ||
|
|
6b5d6e4091 | ||
|
|
a287be1f0c | ||
|
|
42a3149fe3 | ||
|
|
5aee5c0fb8 | ||
|
|
12ecf366b0 | ||
|
|
275562bce0 | ||
|
|
a09030fd6d | ||
|
|
414893a687 | ||
|
|
5939d79057 | ||
|
|
189bd37e71 | ||
|
|
715056047c | ||
|
|
0220f900c1 | ||
|
|
10a0e58572 | ||
|
|
8d47798fa2 | ||
|
|
3f2513a717 | ||
|
|
9be71f603e | ||
|
|
d354b38139 | ||
|
|
1152cd4f07 | ||
|
|
de0e218440 | ||
|
|
d377cf0d02 | ||
|
|
788b435f9b | ||
|
|
6ea91b2dde | ||
|
|
55d883925f | ||
|
|
89aff7764d | ||
|
|
c4e1bc35b4 | ||
|
|
7e53e33e0f | ||
|
|
8b73c2bf8a | ||
|
|
bcb0056b55 | ||
|
|
b1311547b2 | ||
|
|
bddba4bd96 | ||
|
|
8f304b8157 | ||
|
|
6acfac9064 | ||
|
|
f64db3a2f9 | ||
|
|
d1db47ee34 | ||
|
|
3b1f27b674 | ||
|
|
0e753b245a | ||
|
|
8b7d7f1666 | ||
|
|
0f1afff4c3 | ||
|
|
50c36068e7 | ||
|
|
a6f7fdba4e | ||
|
|
9d337bf4dc | ||
|
|
b7d34079d9 | ||
|
|
eade36ee82 | ||
|
|
443d08381a | ||
|
|
4e6880e520 | ||
|
|
9a300d0286 | ||
|
|
9987e3bcef | ||
|
|
cc749858cb | ||
|
|
89264b3da4 | ||
|
|
3aab8ccb4a | ||
|
|
171ba84741 | ||
|
|
83271bb11e | ||
|
|
ffbc9a28ad | ||
|
|
a65fea4d64 | ||
|
|
182ee3c0da | ||
|
|
efe204fef8 | ||
|
|
026308acc9 | ||
|
|
3f60cf5377 | ||
|
|
b07891089f | ||
|
|
4cfac47674 | ||
|
|
f4c90426a5 | ||
|
|
e5d798581c | ||
|
|
05b79eb77b | ||
|
|
4e0fe27de3 | ||
|
|
8eb82836b9 | ||
|
|
5262e92b9f | ||
|
|
c0a6b3d5a3 | ||
|
|
66cd7dd809 | ||
|
|
c90a88fb17 | ||
|
|
de4a699c46 | ||
|
|
149d0da724 | ||
|
|
5340683199 | ||
|
|
652f5cbf20 | ||
|
|
8094b25185 | ||
|
|
bdad18a572 | ||
|
|
a8cbda5f24 | ||
|
|
753d81adad | ||
|
|
43e9529ce4 | ||
|
|
0c258f0506 | ||
|
|
912d5a3069 | ||
|
|
1b6dd9241f | ||
|
|
ecb4ee2e3e | ||
|
|
7a1ae8691e | ||
|
|
92972ac776 | ||
|
|
0c469cc712 | ||
|
|
3e4a14b299 | ||
|
|
dff10e89fe | ||
|
|
693adf8488 | ||
|
|
adacfb1110 | ||
|
|
177cc3d7f9 | ||
|
|
0c582df962 | ||
|
|
1e1fd97b38 | ||
|
|
1e2f02613f | ||
|
|
5a6a726014 | ||
|
|
eace0af7a5 | ||
|
|
036d0556a4 | ||
|
|
e9fda40b2b | ||
|
|
b9b2b559a1 | ||
|
|
5fb3ea465f | ||
|
|
ba04b753de | ||
|
|
92ca447f33 | ||
|
|
755a1331da | ||
|
|
6db541c89b | ||
|
|
67c52c3764 | ||
|
|
131caa20eb | ||
|
|
89a6ed2a5b | ||
|
|
b597cd891b | ||
|
|
fa31a6e441 | ||
|
|
a3688fe642 | ||
|
|
96e786d480 | ||
|
|
3c09482a93 |
19
.editorconfig
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Editor configuration, see https://editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.{ts,js}]
|
||||||
|
quote_type = single
|
||||||
|
|
||||||
|
[*.{md,mdx}]
|
||||||
|
max_line_length = off
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
[*.{yml,yaml}]
|
||||||
|
quote_type = double
|
||||||
24
.github/DISCUSSION_TEMPLATE/feature-request.yaml
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
title: "[Feature] <feature-name-goes-here>"
|
||||||
|
labels: ["feature"]
|
||||||
|
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
Please use this form to request new feature for Immich
|
||||||
|
- type: textarea
|
||||||
|
id: feature
|
||||||
|
attributes:
|
||||||
|
label: The feature
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: checkboxes
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
attributes:
|
||||||
|
label: Platform
|
||||||
|
options:
|
||||||
|
- label: Server
|
||||||
|
- label: Web
|
||||||
|
- label: Mobile
|
||||||
1
.github/FUNDING.yml
vendored
@@ -1,4 +1,5 @@
|
|||||||
# These are supported funding model platforms
|
# These are supported funding model platforms
|
||||||
|
|
||||||
github: alextran1502
|
github: alextran1502
|
||||||
|
liberapay: alex.tran1502
|
||||||
custom: https://www.buymeacoffee.com/altran1502
|
custom: https://www.buymeacoffee.com/altran1502
|
||||||
|
|||||||
46
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,46 +0,0 @@
|
|||||||
---
|
|
||||||
name: Bug report
|
|
||||||
about: Create a report to help us improve
|
|
||||||
title: '[BUG] <title>'
|
|
||||||
labels: bug, need triage
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Note: Please search to see if an issue already exists for the bug you encountered.
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
**Describe the bug**
|
|
||||||
A clear and concise description of what the bug is.
|
|
||||||
|
|
||||||
**Task List**
|
|
||||||
|
|
||||||
*Please complete the task list below. We need this information to help us reproduce the bug or point out problems in your setup. You are not providing enough info may delay our effort to help you.*
|
|
||||||
|
|
||||||
- [ ] I have read thoroughly the README setup and installation instructions.
|
|
||||||
- [ ] I have included my `docker-compose` file.
|
|
||||||
- [ ] I have included my redacted `.env` file.
|
|
||||||
- [ ] I have included information on my machine, and environment.
|
|
||||||
|
|
||||||
**To Reproduce**
|
|
||||||
Steps to reproduce the behavior:
|
|
||||||
1. Go to '...'
|
|
||||||
2. Click on '....'
|
|
||||||
3. Scroll down to '....'
|
|
||||||
4. See error
|
|
||||||
|
|
||||||
**Expected behavior**
|
|
||||||
A clear and concise description of what you expected to happen.
|
|
||||||
|
|
||||||
**Screenshots**
|
|
||||||
If applicable, add screenshots to help explain your problem.
|
|
||||||
|
|
||||||
**System**
|
|
||||||
- Phone OS [iOS, Android]: `<version>`
|
|
||||||
- Server Version: `<version>`
|
|
||||||
- Mobile App Version: `<version>`
|
|
||||||
|
|
||||||
**Additional context**
|
|
||||||
Add any other context about the problem here.
|
|
||||||
100
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
name: Report an issue with Immich
|
||||||
|
description: Report an issue with Immich
|
||||||
|
labels: ["bug", "need triage"]
|
||||||
|
title: "[BUG] <title>"
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
This issue form is for reporting bugs only!
|
||||||
|
|
||||||
|
If you have a feature or enhancement request, please use the [feature request][fr] section of our [GitHub Discussions][fr].
|
||||||
|
|
||||||
|
[fr]: https://github.com/immich-app/immich/discussions/new?category=feature-request
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
attributes:
|
||||||
|
label: The bug
|
||||||
|
description: >-
|
||||||
|
Describe the issue you are experiencing here, to communicate to the
|
||||||
|
maintainers. Tell us what you were trying to do and what happened.
|
||||||
|
|
||||||
|
Provide a clear and concise description of what the problem is.
|
||||||
|
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
## Environment
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
attributes:
|
||||||
|
label: The OS that Immich Server is running on
|
||||||
|
placeholder: Ubuntu 22.10, Debian, Arch...etc
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: version
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
attributes:
|
||||||
|
label: Version of Immich Server
|
||||||
|
placeholder: v1.0.0
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
attributes:
|
||||||
|
label: Version of Immich Mobile App
|
||||||
|
placeholder: v1.0.0
|
||||||
|
|
||||||
|
- type: checkboxes
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
attributes:
|
||||||
|
label: Platform with the issue
|
||||||
|
options:
|
||||||
|
- label: Server
|
||||||
|
- label: Web
|
||||||
|
- label: Mobile
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
attributes:
|
||||||
|
label: Your docker-compose.yml content
|
||||||
|
render: YAML
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
attributes:
|
||||||
|
label: Your .env content
|
||||||
|
description: Please provide the redacted .env content of your setup
|
||||||
|
render: Shell
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: repro
|
||||||
|
attributes:
|
||||||
|
label: Reproduction steps
|
||||||
|
description: "How do you trigger this bug? Please walk us through it step by step."
|
||||||
|
value: |
|
||||||
|
1.
|
||||||
|
2.
|
||||||
|
3.
|
||||||
|
...
|
||||||
|
render: bash
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Additional information
|
||||||
|
description: >
|
||||||
|
If you have any additional information for us, use the field below.
|
||||||
|
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: Thank you for submitting the form
|
||||||
10
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1 +1,11 @@
|
|||||||
blank_issues_enabled: false
|
blank_issues_enabled: false
|
||||||
|
contact_links:
|
||||||
|
- name: I have a question or need support
|
||||||
|
url: https://discord.gg/D8JsnBEuKb
|
||||||
|
about: We use GitHub for tracking bugs, please check out our Discord channel for freaky fast support.
|
||||||
|
- name: Feature Request
|
||||||
|
url: https://github.com/immich-app/immich/discussions/new?category=feature-request
|
||||||
|
about: Please use our GitHub Discussion for making feature requests.
|
||||||
|
- name: I'm unsure where to go
|
||||||
|
url: https://discord.gg/D8JsnBEuKb
|
||||||
|
about: If you are unsure where to go, then joining our Discord is recommended; Just ask!
|
||||||
|
|||||||
32
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
@@ -1,32 +0,0 @@
|
|||||||
name: Feature Request
|
|
||||||
description: Request a feature that you would like for the app
|
|
||||||
title: "[Feature]: "
|
|
||||||
labels: ["feature", "need triage"]
|
|
||||||
assignees:
|
|
||||||
- ""
|
|
||||||
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
Thanks for taking the time to fill out this feature request!
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: feature-detail
|
|
||||||
attributes:
|
|
||||||
label: Feature detail
|
|
||||||
placeholder: Describe the feature you would like to see for the app
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: dropdown
|
|
||||||
id: platform
|
|
||||||
attributes:
|
|
||||||
label: Platform
|
|
||||||
description: Choose the platform for the feature
|
|
||||||
options:
|
|
||||||
- Web
|
|
||||||
- Mobile App
|
|
||||||
- Server
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
73
.github/workflows/build-mobile.yml
vendored
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
name: Build Mobile
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
ref:
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
pull_request:
|
||||||
|
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:
|
||||||
|
- name: Determine ref
|
||||||
|
id: get-ref
|
||||||
|
run: |
|
||||||
|
input_ref="${{ inputs.ref }}"
|
||||||
|
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 }}
|
||||||
|
|
||||||
|
- uses: actions/setup-java@v3
|
||||||
|
with:
|
||||||
|
distribution: "zulu"
|
||||||
|
java-version: "12.x"
|
||||||
|
cache: "gradle"
|
||||||
|
|
||||||
|
- name: Setup Flutter SDK
|
||||||
|
uses: subosito/flutter-action@v2
|
||||||
|
with:
|
||||||
|
channel: "stable"
|
||||||
|
flutter-version: "3.7.3"
|
||||||
|
cache: true
|
||||||
|
|
||||||
|
- name: Create the Keystore
|
||||||
|
env:
|
||||||
|
KEY_JKS: ${{ secrets.KEY_JKS }}
|
||||||
|
working-directory: ./mobile
|
||||||
|
run: echo $KEY_JKS | base64 -d > android/key.jks
|
||||||
|
|
||||||
|
- name: Get Packages
|
||||||
|
working-directory: ./mobile
|
||||||
|
run: flutter pub get
|
||||||
|
|
||||||
|
- name: Build Android App Bundle
|
||||||
|
working-directory: ./mobile
|
||||||
|
env:
|
||||||
|
ALIAS: ${{ secrets.ALIAS }}
|
||||||
|
ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
|
||||||
|
ANDROID_STORE_PASSWORD: ${{ secrets.ANDROID_STORE_PASSWORD }}
|
||||||
|
run: flutter build apk --release
|
||||||
|
|
||||||
|
- name: Publish Android Artifact
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: release-apk-signed
|
||||||
|
path: mobile/build/app/outputs/flutter-apk/app-release.apk
|
||||||
152
.github/workflows/build_push_docker_latest.yml
vendored
@@ -1,152 +0,0 @@
|
|||||||
name: Build and Push Docker Image - Latest
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
|
||||||
branches: [main]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
# This image include both the server and microservices - the two containers can be slitted into separated
|
|
||||||
# service with its coressponding entry file.
|
|
||||||
build_and_push_server_monorepo_latest:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v2.1.0
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
id: buildx
|
|
||||||
uses: docker/setup-buildx-action@v2.2.1
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
- name: Login to GitHub Container Registry
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Build and push Immich Mono Repo
|
|
||||||
uses: docker/build-push-action@v3.2.0
|
|
||||||
with:
|
|
||||||
context: ./server
|
|
||||||
file: ./server/Dockerfile
|
|
||||||
platforms: linux/arm/v7,linux/amd64,linux/arm64
|
|
||||||
push: true
|
|
||||||
cache-from: type=gha
|
|
||||||
cache-to: type=gha,mode=max
|
|
||||||
tags: |
|
|
||||||
altran1502/immich-server:latest
|
|
||||||
ghcr.io/${{ github.repository_owner }}/immich-server:latest
|
|
||||||
|
|
||||||
build_and_push_machine_learning_latest:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v2.1.0
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
id: buildx
|
|
||||||
uses: docker/setup-buildx-action@v2.2.1
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
- name: Login to GitHub Container Registry
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Build and Push Machine Learning
|
|
||||||
uses: docker/build-push-action@v3.2.0
|
|
||||||
with:
|
|
||||||
context: ./machine-learning
|
|
||||||
file: ./machine-learning/Dockerfile
|
|
||||||
platforms: linux/arm/v7,linux/amd64,linux/arm64
|
|
||||||
push: true
|
|
||||||
cache-from: type=gha
|
|
||||||
cache-to: type=gha,mode=max
|
|
||||||
tags: |
|
|
||||||
altran1502/immich-machine-learning:latest
|
|
||||||
ghcr.io/${{ github.repository_owner }}/immich-machine-learning:latest
|
|
||||||
|
|
||||||
build_and_push_web_latest:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v2.1.0
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
id: buildx
|
|
||||||
uses: docker/setup-buildx-action@v2.2.1
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
- name: Login to GitHub Container Registry
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Build and Push Web
|
|
||||||
uses: docker/build-push-action@v3.2.0
|
|
||||||
with:
|
|
||||||
context: ./web
|
|
||||||
file: ./web/Dockerfile
|
|
||||||
platforms: linux/arm/v7,linux/amd64,linux/arm64
|
|
||||||
target: prod
|
|
||||||
push: true
|
|
||||||
tags: |
|
|
||||||
altran1502/immich-web:latest
|
|
||||||
ghcr.io/${{ github.repository_owner }}/immich-web:latest
|
|
||||||
|
|
||||||
build_and_push_nginx_latest:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v2.1.0
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
id: buildx
|
|
||||||
uses: docker/setup-buildx-action@v2.2.1
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
- name: Login to GitHub Container Registry
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Build and Push Proxy
|
|
||||||
uses: docker/build-push-action@v3.2.0
|
|
||||||
with:
|
|
||||||
context: ./nginx
|
|
||||||
file: ./nginx/Dockerfile
|
|
||||||
platforms: linux/arm/v7,linux/amd64,linux/arm64
|
|
||||||
push: true
|
|
||||||
tags: |
|
|
||||||
altran1502/immich-proxy:latest
|
|
||||||
ghcr.io/${{ github.repository_owner }}/immich-proxy:latest
|
|
||||||
168
.github/workflows/build_push_docker_staging.yml
vendored
@@ -1,168 +0,0 @@
|
|||||||
name: Build and Push Docker Image - Staging
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
pull_request:
|
|
||||||
branches: [main]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
# This image include both the server and microservices - the two containers can be slitted into separated
|
|
||||||
# service with its coressponding entry file.
|
|
||||||
build_and_push_server_monorepo_staging:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v2.1.0
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
id: buildx
|
|
||||||
uses: docker/setup-buildx-action@v2.2.1
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
if: ${{ github.repository == 'immich-app/immich' }}
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
- name: Login to GitHub Container Registry
|
|
||||||
if: ${{ github.repository == 'immich-app/immich' }}
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Build and push Immich Mono Repo
|
|
||||||
uses: docker/build-push-action@v3.2.0
|
|
||||||
with:
|
|
||||||
context: ./server
|
|
||||||
file: ./server/Dockerfile
|
|
||||||
platforms: linux/arm/v7,linux/amd64,linux/arm64
|
|
||||||
push: ${{ github.event_name == 'pull_request' && github.repository == 'immich-app/immich' }}
|
|
||||||
cache-from: type=gha
|
|
||||||
cache-to: type=gha,mode=max
|
|
||||||
tags: |
|
|
||||||
altran1502/immich-server:staging
|
|
||||||
altran1502/immich-server:${{ github.event.pull_request.number }}
|
|
||||||
ghcr.io/${{ github.repository_owner }}/immich-server:staging
|
|
||||||
ghcr.io/${{ github.repository_owner }}/immich-server:${{ github.event.pull_request.number }}
|
|
||||||
|
|
||||||
build_and_push_machine_learning_staging:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v2.1.0
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
id: buildx
|
|
||||||
uses: docker/setup-buildx-action@v2.2.1
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
if: ${{ github.repository == 'immich-app/immich' }}
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
- name: Login to GitHub Container Registry
|
|
||||||
if: ${{ github.repository == 'immich-app/immich' }}
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Build and Push Machine Learning
|
|
||||||
uses: docker/build-push-action@v3.2.0
|
|
||||||
with:
|
|
||||||
context: ./machine-learning
|
|
||||||
file: ./machine-learning/Dockerfile
|
|
||||||
platforms: linux/arm/v7,linux/amd64,linux/arm64
|
|
||||||
push: ${{ github.event_name == 'pull_request' && github.repository == 'immich-app/immich' }}
|
|
||||||
cache-from: type=gha
|
|
||||||
cache-to: type=gha,mode=max
|
|
||||||
tags: |
|
|
||||||
altran1502/immich-machine-learning:staging
|
|
||||||
altran1502/immich-machine-learning:${{ github.event.pull_request.number }}
|
|
||||||
ghcr.io/${{ github.repository_owner }}/immich-machine-learning:staging
|
|
||||||
ghcr.io/${{ github.repository_owner }}/immich-machine-learning:${{ github.event.pull_request.number }}
|
|
||||||
|
|
||||||
build_and_push_web_staging:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v2.1.0
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
id: buildx
|
|
||||||
uses: docker/setup-buildx-action@v2.2.1
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
if: ${{ github.repository == 'immich-app/immich' }}
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
- name: Login to GitHub Container Registry
|
|
||||||
if: ${{ github.repository == 'immich-app/immich' }}
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Build and Push Web
|
|
||||||
uses: docker/build-push-action@v3.2.0
|
|
||||||
with:
|
|
||||||
context: ./web
|
|
||||||
file: ./web/Dockerfile
|
|
||||||
platforms: linux/arm/v7,linux/amd64,linux/arm64
|
|
||||||
target: prod
|
|
||||||
push: ${{ github.event_name == 'pull_request' && github.repository == 'immich-app/immich' }}
|
|
||||||
tags: |
|
|
||||||
altran1502/immich-web:staging
|
|
||||||
altran1502/immich-web:${{ github.event.pull_request.number }}
|
|
||||||
ghcr.io/${{ github.repository_owner }}/immich-web:staging
|
|
||||||
ghcr.io/${{ github.repository_owner }}/immich-web:${{ github.event.pull_request.number }}
|
|
||||||
|
|
||||||
build_and_push_nginx_staging:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v2.1.0
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
id: buildx
|
|
||||||
uses: docker/setup-buildx-action@v2.2.1
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
if: ${{ github.repository == 'immich-app/immich' }}
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
- name: Login to GitHub Container Registry
|
|
||||||
if: ${{ github.repository == 'immich-app/immich' }}
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Build and Push Proxy
|
|
||||||
uses: docker/build-push-action@v3.2.0
|
|
||||||
with:
|
|
||||||
context: ./nginx
|
|
||||||
file: ./nginx/Dockerfile
|
|
||||||
platforms: linux/arm/v7,linux/amd64,linux/arm64
|
|
||||||
push: ${{ github.event_name == 'pull_request' && github.repository == 'immich-app/immich' }}
|
|
||||||
tags: |
|
|
||||||
altran1502/immich-proxy:staging
|
|
||||||
altran1502/immich-proxy:${{ github.event.pull_request.number }}
|
|
||||||
ghcr.io/${{ github.repository_owner }}/immich-proxy:staging
|
|
||||||
ghcr.io/${{ github.repository_owner }}/immich-proxy:${{ github.event.pull_request.number }}
|
|
||||||
197
.github/workflows/build_push_server_release.yml
vendored
@@ -1,197 +0,0 @@
|
|||||||
name: Build and push Docker image - Release
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
release:
|
|
||||||
types: [published]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build_and_push_server_monorepo_release:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
ref: 'main'
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: 'Get Previous tag'
|
|
||||||
id: previoustag
|
|
||||||
uses: 'WyriHaximus/github-action-get-previous-tag@v1'
|
|
||||||
with:
|
|
||||||
fallback: latest
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v2.1.0
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
id: buildx
|
|
||||||
uses: docker/setup-buildx-action@v2.2.1
|
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Build and push immich-server release
|
|
||||||
uses: docker/build-push-action@v3.2.0
|
|
||||||
with:
|
|
||||||
context: ./server
|
|
||||||
file: ./server/Dockerfile
|
|
||||||
platforms: linux/arm/v7,linux/amd64,linux/arm64
|
|
||||||
push: ${{ github.event_name != 'pull_request' }}
|
|
||||||
cache-from: type=gha
|
|
||||||
cache-to: type=gha,mode=max
|
|
||||||
tags: |
|
|
||||||
altran1502/immich-server:${{ steps.previoustag.outputs.tag }}
|
|
||||||
altran1502/immich-server:release
|
|
||||||
ghcr.io/${{ github.repository_owner }}/immich-server:${{ steps.previoustag.outputs.tag }}
|
|
||||||
ghcr.io/${{ github.repository_owner }}/immich-server:release
|
|
||||||
|
|
||||||
build_and_push_machine_learning_release:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: 'Get Previous tag'
|
|
||||||
id: previoustag
|
|
||||||
uses: 'WyriHaximus/github-action-get-previous-tag@v1'
|
|
||||||
with:
|
|
||||||
fallback: latest
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v2.1.0
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
id: buildx
|
|
||||||
uses: docker/setup-buildx-action@v2.2.1
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
- name: Login to GitHub Container Registry
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Build and Push Machine Learning
|
|
||||||
uses: docker/build-push-action@v3.2.0
|
|
||||||
with:
|
|
||||||
context: ./machine-learning
|
|
||||||
file: ./machine-learning/Dockerfile
|
|
||||||
platforms: linux/arm/v7,linux/amd64,linux/arm64
|
|
||||||
push: true
|
|
||||||
cache-from: type=gha
|
|
||||||
cache-to: type=gha,mode=max
|
|
||||||
tags: |
|
|
||||||
altran1502/immich-machine-learning:${{ steps.previoustag.outputs.tag }}
|
|
||||||
altran1502/immich-machine-learning:release
|
|
||||||
ghcr.io/${{ github.repository_owner }}/immich-machine-learning:${{ steps.previoustag.outputs.tag }}
|
|
||||||
ghcr.io/${{ github.repository_owner }}/immich-machine-learning:release
|
|
||||||
|
|
||||||
build_and_push_web_release:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
ref: 'main'
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: 'Get Previous tag'
|
|
||||||
id: previoustag
|
|
||||||
uses: 'WyriHaximus/github-action-get-previous-tag@v1'
|
|
||||||
with:
|
|
||||||
fallback: latest
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v2.1.0
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
id: buildx
|
|
||||||
uses: docker/setup-buildx-action@v2.2.1
|
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Build and push immich-web release
|
|
||||||
uses: docker/build-push-action@v3.2.0
|
|
||||||
with:
|
|
||||||
context: ./web
|
|
||||||
file: ./web/Dockerfile
|
|
||||||
platforms: linux/arm/v7,linux/amd64,linux/arm64
|
|
||||||
push: ${{ github.event_name != 'pull_request' }}
|
|
||||||
target: prod
|
|
||||||
tags: |
|
|
||||||
altran1502/immich-web:${{ steps.previoustag.outputs.tag }}
|
|
||||||
altran1502/immich-web:release
|
|
||||||
ghcr.io/${{ github.repository_owner }}/immich-web:${{ steps.previoustag.outputs.tag }}
|
|
||||||
ghcr.io/${{ github.repository_owner }}/immich-web:release
|
|
||||||
|
|
||||||
build_and_push_nginx_release:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
ref: 'main'
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: 'Get Previous tag'
|
|
||||||
id: previoustag
|
|
||||||
uses: 'WyriHaximus/github-action-get-previous-tag@v1'
|
|
||||||
with:
|
|
||||||
fallback: latest
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v2.1.0
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
id: buildx
|
|
||||||
uses: docker/setup-buildx-action@v2.2.1
|
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Build and push immich-proxy release
|
|
||||||
uses: docker/build-push-action@v3.2.0
|
|
||||||
with:
|
|
||||||
context: ./nginx
|
|
||||||
file: ./nginx/Dockerfile
|
|
||||||
platforms: linux/arm/v7,linux/amd64,linux/arm64
|
|
||||||
push: ${{ github.event_name != 'pull_request' }}
|
|
||||||
tags: |
|
|
||||||
altran1502/immich-proxy:release
|
|
||||||
altran1502/immich-proxy:${{ steps.previoustag.outputs.tag }}
|
|
||||||
ghcr.io/${{ github.repository_owner }}/immich-proxy:${{ steps.previoustag.outputs.tag }}
|
|
||||||
ghcr.io/${{ github.repository_owner }}/immich-proxy:release
|
|
||||||
37
.github/workflows/cache-cleanup.yml
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
name: Clean up actions cache on PR close
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
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.
|
||||||
|
set +e
|
||||||
|
echo "Deleting caches..."
|
||||||
|
for cacheKey in $cacheKeysForPR
|
||||||
|
do
|
||||||
|
gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm
|
||||||
|
done
|
||||||
|
echo "Done"
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
10
.github/workflows/codeql-analysis.yml
vendored
@@ -20,6 +20,10 @@ on:
|
|||||||
schedule:
|
schedule:
|
||||||
- cron: '20 13 * * 1'
|
- cron: '20 13 * * 1'
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
analyze:
|
analyze:
|
||||||
name: 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.
|
# 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.
|
# 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.
|
# 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
|
# 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
|
# queries: security-extended,security-and-quality
|
||||||
|
|
||||||
|
|
||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
# 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)
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
@@ -61,7 +65,7 @@ jobs:
|
|||||||
# ℹ️ Command-line programs to run using the OS shell.
|
# ℹ️ 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
|
# 📚 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.
|
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
||||||
|
|
||||||
# - run: |
|
# - run: |
|
||||||
|
|||||||
5
.github/workflows/dispatch_sdk_update.yml
vendored
@@ -5,9 +5,14 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches: ["main"]
|
branches: ["main"]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
update-sdk-repos:
|
update-sdk-repos:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
if: ${{ !github.event.pull_request.head.repo.fork }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/github-script@v6
|
- uses: actions/github-script@v6
|
||||||
with:
|
with:
|
||||||
|
|||||||
109
.github/workflows/docker.yml
vendored
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
name: Build and Push Docker Images
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build_and_push:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
# Prevent a failure in one image from stopping the other builds
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
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
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v2.1.0
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
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
|
||||||
|
with:
|
||||||
|
driver-opts: |
|
||||||
|
image=moby/buildkit:v0.10.6
|
||||||
|
|
||||||
|
- name: Login to Docker Hub
|
||||||
|
# Only push to Docker Hub when making a release
|
||||||
|
if: ${{ github.event_name == 'release' }}
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
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
|
||||||
|
if: ${{ !github.event.pull_request.head.repo.fork }}
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.repository_owner }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Generate docker image tags
|
||||||
|
id: metadata
|
||||||
|
uses: docker/metadata-action@v4
|
||||||
|
with:
|
||||||
|
flavor: |
|
||||||
|
# Disable latest tag
|
||||||
|
latest=false
|
||||||
|
images: |
|
||||||
|
name=ghcr.io/${{ github.repository_owner }}/${{matrix.image}}
|
||||||
|
name=altran1502/${{matrix.image}},enable=${{ github.event_name == 'release' }}
|
||||||
|
tags: |
|
||||||
|
# Tag with branch name
|
||||||
|
type=ref,event=branch
|
||||||
|
# Tag with pr-number
|
||||||
|
type=ref,event=pr
|
||||||
|
# Tag with git tag on release
|
||||||
|
type=ref,event=tag
|
||||||
|
type=raw,value=release,enable=${{ github.event_name == 'release' }}
|
||||||
|
|
||||||
|
- name: Determine build cache output
|
||||||
|
id: cache-target
|
||||||
|
run: |
|
||||||
|
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
|
||||||
|
# Essentially just ignore the cache output (PR can't write to registry cache)
|
||||||
|
echo "cache-to=type=local,dest=/tmp/discard,ignore-error=true" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "cache-to=type=registry,mode=max,ref=ghcr.io/${{ github.repository_owner }}/immich-build-cache:${{ matrix.image }}" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Build and push image
|
||||||
|
uses: docker/build-push-action@v4.0.0
|
||||||
|
with:
|
||||||
|
context: ${{ matrix.context }}
|
||||||
|
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}}
|
||||||
|
cache-to: ${{ steps.cache-target.outputs.cache-to }}
|
||||||
|
tags: ${{ steps.metadata.outputs.tags }}
|
||||||
|
labels: ${{ steps.metadata.outputs.labels }}
|
||||||
4
.github/workflows/github-repo-stats.yml
vendored
@@ -7,6 +7,10 @@ on:
|
|||||||
- cron: "0 23 * * *"
|
- cron: "0 23 * * *"
|
||||||
workflow_dispatch: # Allow for running this manually.
|
workflow_dispatch: # Allow for running this manually.
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
j1:
|
j1:
|
||||||
name: github-repo-stats
|
name: github-repo-stats
|
||||||
|
|||||||
83
.github/workflows/prepare-release.yml
vendored
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
name: Prepare new release
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
serverBump:
|
||||||
|
description: "Bump server version"
|
||||||
|
required: true
|
||||||
|
default: "false"
|
||||||
|
type: choice
|
||||||
|
options:
|
||||||
|
- "false"
|
||||||
|
- minor
|
||||||
|
- patch
|
||||||
|
mobileBump:
|
||||||
|
description: "Bump mobile build number"
|
||||||
|
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
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.ORG_RELEASE_TOKEN }}
|
||||||
|
|
||||||
|
- name: Bump version
|
||||||
|
run: misc/release/pump-version.sh -s "${{ inputs.serverBump }}" -m "${{ inputs.mobileBump }}"
|
||||||
|
|
||||||
|
- name: Commit and tag
|
||||||
|
id: push-tag
|
||||||
|
uses: EndBug/add-and-commit@v9
|
||||||
|
with:
|
||||||
|
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
|
||||||
|
secrets: inherit
|
||||||
|
with:
|
||||||
|
ref: ${{ needs.bump_version.outputs.ref }}
|
||||||
|
|
||||||
|
prepare_release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: build_mobile
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.ORG_RELEASE_TOKEN }}
|
||||||
|
|
||||||
|
- name: Download APK
|
||||||
|
uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
name: release-apk-signed
|
||||||
|
|
||||||
|
- name: Create draft release
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
with:
|
||||||
|
draft: true
|
||||||
|
tag_name: ${{ env.IMMICH_VERSION }}
|
||||||
|
generate_release_notes: true
|
||||||
|
body_path: misc/release/notes.tmpl
|
||||||
|
files: |
|
||||||
|
docker/docker-compose.yml
|
||||||
|
docker/example.env
|
||||||
|
*.apk
|
||||||
35
.github/workflows/static_analysis.yml
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
name: Static Code Analysis
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
mobile-dart-analyze:
|
||||||
|
name: Run Dart Code Analysis
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Setup Flutter SDK
|
||||||
|
uses: subosito/flutter-action@v2
|
||||||
|
with:
|
||||||
|
channel: 'stable'
|
||||||
|
flutter-version: '3.7.3'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: dart pub get
|
||||||
|
working-directory: ./mobile
|
||||||
|
|
||||||
|
- name: Run dart analyze
|
||||||
|
run: dart analyze --fatal-infos
|
||||||
|
working-directory: ./mobile
|
||||||
|
|
||||||
159
.github/workflows/test.yml
vendored
@@ -5,6 +5,10 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches: [main]
|
branches: [main]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
e2e-tests:
|
e2e-tests:
|
||||||
name: Run end-to-end test suites
|
name: Run end-to-end test suites
|
||||||
@@ -39,3 +43,158 @@ jobs:
|
|||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: cd web && npm ci && npm run check:all
|
run: cd web && npm ci && npm run check:all
|
||||||
|
|
||||||
|
mobile-unit-tests:
|
||||||
|
name: Run mobile unit tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Setup Flutter SDK
|
||||||
|
uses: subosito/flutter-action@v2
|
||||||
|
with:
|
||||||
|
channel: "stable"
|
||||||
|
flutter-version: "3.7.3"
|
||||||
|
- name: Run tests
|
||||||
|
working-directory: ./mobile
|
||||||
|
run: flutter test
|
||||||
|
|
||||||
|
generated-api-up-to-date:
|
||||||
|
name: Check generated files are up-to-date
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@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:
|
||||||
|
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/db/migrations/TestMigration
|
||||||
|
- name: Find file changes
|
||||||
|
uses: tj-actions/verify-changed-files@v13.1
|
||||||
|
id: verify-changed-files
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
server/libs/infra/src/db/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
|
||||||
|
|||||||
6
.gitignore
vendored
@@ -4,3 +4,9 @@
|
|||||||
.idea
|
.idea
|
||||||
|
|
||||||
docker/upload
|
docker/upload
|
||||||
|
uploads
|
||||||
|
coverage
|
||||||
|
|
||||||
|
mobile/gradle.properties
|
||||||
|
mobile/openapi/pubspec.lock
|
||||||
|
mobile/*.jks
|
||||||
|
|||||||
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.
|
|
||||||
42
README.md
@@ -61,24 +61,25 @@ Spec: Free-tier Oracle VM - Amsterdam - 2.4Ghz quad-core ARM64 CPU, 24GB RAM
|
|||||||
|
|
||||||
# Features
|
# Features
|
||||||
|
|
||||||
| Features | Mobile | Web |
|
| Features | Mobile | Web |
|
||||||
| ------------------------------------------- | ------- | --- |
|
| ------------------------------------------- | ------ | --- |
|
||||||
| Upload and view videos and photos | Yes | Yes |
|
| Upload and view videos and photos | Yes | Yes |
|
||||||
| Auto backup when the app is opened | Yes | N/A |
|
| Auto backup when the app is opened | Yes | N/A |
|
||||||
| Selective album(s) for backup | Yes | N/A |
|
| Selective album(s) for backup | Yes | N/A |
|
||||||
| Download photos and videos to local device | Yes | Yes |
|
| Download photos and videos to local device | Yes | Yes |
|
||||||
| Multi-user support | Yes | Yes |
|
| Multi-user support | Yes | Yes |
|
||||||
| Album and Shared albums | Yes | Yes |
|
| Album and Shared albums | Yes | Yes |
|
||||||
| Scrubbable/draggable scrollbar | Yes | Yes |
|
| Scrubbable/draggable scrollbar | Yes | Yes |
|
||||||
| Support RAW (HEIC, HEIF, DNG, Apple ProRaw) | Yes | Yes |
|
| Support RAW (HEIC, HEIF, DNG, Apple ProRaw) | Yes | Yes |
|
||||||
| Metadata view (EXIF, map) | Yes | Yes |
|
| Metadata view (EXIF, map) | Yes | Yes |
|
||||||
| Search by metadata, objects and image tags | Yes | No |
|
| Search by metadata, objects and image tags | Yes | No |
|
||||||
| Administrative functions (user management) | N/A | Yes |
|
| Administrative functions (user management) | N/A | Yes |
|
||||||
| Background backup | Android | N/A |
|
| Background backup | Yes | N/A |
|
||||||
| Virtual scroll | Yes | Yes |
|
| Virtual scroll | Yes | Yes |
|
||||||
| OAuth support | Yes | Yes |
|
| OAuth support | Yes | Yes |
|
||||||
| LivePhoto backup and playback | iOS | Yes |
|
| LivePhoto backup and playback | iOS | Yes |
|
||||||
| User-defined storage structure | Yes | Yes |
|
| User-defined storage structure | Yes | Yes |
|
||||||
|
| Public Sharing | N/A | Yes |
|
||||||
|
|
||||||
# Support the project
|
# Support the project
|
||||||
|
|
||||||
@@ -91,7 +92,10 @@ If you feel like this is the right cause and the app is something you are seeing
|
|||||||
## Donation
|
## Donation
|
||||||
|
|
||||||
- [Monthly donation](https://github.com/sponsors/alextran1502) via GitHub Sponsors
|
- [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
|
||||||
|
|
||||||
# Known Issues
|
# Known Issues
|
||||||
|
|
||||||
|
|||||||
@@ -5,14 +5,11 @@ DB_PASSWORD=postgres
|
|||||||
DB_DATABASE_NAME=e2e_test
|
DB_DATABASE_NAME=e2e_test
|
||||||
|
|
||||||
# Redis
|
# Redis
|
||||||
REDIS_HOSTNAME=immich_redis_test
|
REDIS_HOSTNAME=immich-redis-test
|
||||||
|
|
||||||
# Upload File Config
|
# Upload File Config
|
||||||
UPLOAD_LOCATION=./upload
|
UPLOAD_LOCATION=./upload
|
||||||
|
|
||||||
# JWT SECRET
|
|
||||||
JWT_SECRET=randomstringthatissolongandpowerfulthatnoonecanguess
|
|
||||||
|
|
||||||
# MAPBOX
|
# MAPBOX
|
||||||
## ENABLE_MAPBOX is either true of false -> if true, you have to provide MAPBOX_KEY
|
## ENABLE_MAPBOX is either true of false -> if true, you have to provide MAPBOX_KEY
|
||||||
ENABLE_MAPBOX=false
|
ENABLE_MAPBOX=false
|
||||||
@@ -20,3 +17,5 @@ ENABLE_MAPBOX=false
|
|||||||
# WEB
|
# WEB
|
||||||
MAPBOX_KEY=
|
MAPBOX_KEY=
|
||||||
VITE_SERVER_ENDPOINT=http://localhost:2283/api
|
VITE_SERVER_ENDPOINT=http://localhost:2283/api
|
||||||
|
|
||||||
|
TYPESENSE_ENABLED=false
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
version: '3.8'
|
version: "3.8"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
immich-server:
|
immich-server:
|
||||||
@@ -14,6 +14,7 @@ services:
|
|||||||
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
||||||
- /usr/src/app/node_modules
|
- /usr/src/app/node_modules
|
||||||
ports:
|
ports:
|
||||||
|
- 3001:3001
|
||||||
- 9230:9230
|
- 9230:9230
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
@@ -22,6 +23,7 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
- redis
|
- redis
|
||||||
- database
|
- database
|
||||||
|
- typesense
|
||||||
|
|
||||||
immich-machine-learning:
|
immich-machine-learning:
|
||||||
container_name: immich_machine_learning
|
container_name: immich_machine_learning
|
||||||
@@ -29,18 +31,20 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: ../machine-learning
|
context: ../machine-learning
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
target: builder
|
command: python main.py
|
||||||
command: npm run start:dev
|
ports:
|
||||||
|
- 3003:3003
|
||||||
volumes:
|
volumes:
|
||||||
- ../machine-learning:/usr/src/app
|
- ../machine-learning/src:/usr/src/app
|
||||||
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
||||||
- /usr/src/app/node_modules
|
- model-cache:/cache
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
environment:
|
environment:
|
||||||
- NODE_ENV=development
|
- NODE_ENV=development
|
||||||
depends_on:
|
depends_on:
|
||||||
- database
|
- database
|
||||||
|
restart: always
|
||||||
|
|
||||||
immich-microservices:
|
immich-microservices:
|
||||||
container_name: immich_microservices
|
container_name: immich_microservices
|
||||||
@@ -61,6 +65,7 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
- database
|
- database
|
||||||
- immich-server
|
- immich-server
|
||||||
|
- typesense
|
||||||
|
|
||||||
immich-web:
|
immich-web:
|
||||||
container_name: immich_web
|
container_name: immich_web
|
||||||
@@ -75,6 +80,7 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
# Rename these values for svelte public interface
|
# Rename these values for svelte public interface
|
||||||
- PUBLIC_IMMICH_SERVER_URL=${IMMICH_SERVER_URL}
|
- PUBLIC_IMMICH_SERVER_URL=${IMMICH_SERVER_URL}
|
||||||
|
- PUBLIC_IMMICH_API_URL_EXTERNAL=${IMMICH_API_URL_EXTERNAL}
|
||||||
ports:
|
ports:
|
||||||
- 3000:3000
|
- 3000:3000
|
||||||
- 24678:24678
|
- 24678:24678
|
||||||
@@ -85,6 +91,17 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
- immich-server
|
- 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:
|
redis:
|
||||||
container_name: immich_redis
|
container_name: immich_redis
|
||||||
image: redis:6.2
|
image: redis:6.2
|
||||||
@@ -124,3 +141,5 @@ services:
|
|||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
pgdata:
|
pgdata:
|
||||||
|
model-cache:
|
||||||
|
tsdata:
|
||||||
|
|||||||
@@ -1,94 +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}
|
|
||||||
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:
|
services:
|
||||||
immich-server-test:
|
immich-server-test:
|
||||||
@@ -9,7 +9,7 @@ services:
|
|||||||
target: builder
|
target: builder
|
||||||
command: npm run test:e2e
|
command: npm run test:e2e
|
||||||
expose:
|
expose:
|
||||||
- '3000'
|
- "3000"
|
||||||
volumes:
|
volumes:
|
||||||
- ../server:/usr/src/app
|
- ../server:/usr/src/app
|
||||||
- /usr/src/app/node_modules
|
- /usr/src/app/node_modules
|
||||||
@@ -17,6 +17,7 @@ services:
|
|||||||
- .env.test
|
- .env.test
|
||||||
environment:
|
environment:
|
||||||
- NODE_ENV=development
|
- NODE_ENV=development
|
||||||
|
- TYPESENSE_ENABLED=false
|
||||||
depends_on:
|
depends_on:
|
||||||
- immich-redis-test
|
- immich-redis-test
|
||||||
- immich-database-test
|
- immich-database-test
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ version: "3.8"
|
|||||||
services:
|
services:
|
||||||
immich-server:
|
immich-server:
|
||||||
container_name: 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"]
|
entrypoint: ["/bin/sh", "./start-server.sh"]
|
||||||
volumes:
|
volumes:
|
||||||
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
||||||
@@ -14,11 +14,12 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
- redis
|
- redis
|
||||||
- database
|
- database
|
||||||
|
- typesense
|
||||||
restart: always
|
restart: always
|
||||||
|
|
||||||
immich-microservices:
|
immich-microservices:
|
||||||
container_name: 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"]
|
entrypoint: ["/bin/sh", "./start-microservices.sh"]
|
||||||
volumes:
|
volumes:
|
||||||
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
||||||
@@ -29,31 +30,39 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
- redis
|
- redis
|
||||||
- database
|
- database
|
||||||
|
- typesense
|
||||||
restart: always
|
restart: always
|
||||||
|
|
||||||
immich-machine-learning:
|
immich-machine-learning:
|
||||||
container_name: immich_machine_learning
|
container_name: immich_machine_learning
|
||||||
image: altran1502/immich-machine-learning:release
|
image: ghcr.io/immich-app/immich-machine-learning:release
|
||||||
entrypoint: ["/bin/sh", "./entrypoint.sh"]
|
|
||||||
volumes:
|
volumes:
|
||||||
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
||||||
|
- model-cache:/cache
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
environment:
|
environment:
|
||||||
- NODE_ENV=production
|
- NODE_ENV=production
|
||||||
depends_on:
|
|
||||||
- database
|
|
||||||
restart: always
|
restart: always
|
||||||
|
|
||||||
immich-web:
|
immich-web:
|
||||||
container_name: immich_web
|
container_name: immich_web
|
||||||
image: altran1502/immich-web:release
|
image: ghcr.io/immich-app/immich-web:release
|
||||||
entrypoint: ["/bin/sh", "./entrypoint.sh"]
|
entrypoint: ["/bin/sh", "./entrypoint.sh"]
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
|
restart: always
|
||||||
|
|
||||||
|
typesense:
|
||||||
|
container_name: immich_typesense
|
||||||
|
image: typesense/typesense:0.24.0
|
||||||
environment:
|
environment:
|
||||||
# Rename these values for svelte public interface
|
- TYPESENSE_API_KEY=${TYPESENSE_API_KEY}
|
||||||
- PUBLIC_IMMICH_SERVER_URL=${IMMICH_SERVER_URL}
|
- TYPESENSE_DATA_DIR=/data
|
||||||
|
logging:
|
||||||
|
driver: none
|
||||||
|
volumes:
|
||||||
|
- tsdata:/data
|
||||||
restart: always
|
restart: always
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
@@ -77,7 +86,7 @@ services:
|
|||||||
|
|
||||||
immich-proxy:
|
immich-proxy:
|
||||||
container_name: immich_proxy
|
container_name: immich_proxy
|
||||||
image: altran1502/immich-proxy:release
|
image: ghcr.io/immich-app/immich-proxy:release
|
||||||
environment:
|
environment:
|
||||||
# Make sure these values get passed through from the env file
|
# Make sure these values get passed through from the env file
|
||||||
- IMMICH_SERVER_URL
|
- IMMICH_SERVER_URL
|
||||||
@@ -92,3 +101,5 @@ services:
|
|||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
pgdata:
|
pgdata:
|
||||||
|
model-cache:
|
||||||
|
tsdata:
|
||||||
|
|||||||
@@ -17,6 +17,11 @@ DB_DATABASE_NAME=immich
|
|||||||
REDIS_HOSTNAME=immich_redis
|
REDIS_HOSTNAME=immich_redis
|
||||||
|
|
||||||
# Optional Redis settings:
|
# 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_PORT=6379
|
||||||
# REDIS_DBINDEX=0
|
# REDIS_DBINDEX=0
|
||||||
# REDIS_PASSWORD=
|
# REDIS_PASSWORD=
|
||||||
@@ -30,15 +35,12 @@ REDIS_HOSTNAME=immich_redis
|
|||||||
|
|
||||||
UPLOAD_LOCATION=absolute_location_on_your_machine_where_you_want_to_store_the_backup
|
UPLOAD_LOCATION=absolute_location_on_your_machine_where_you_want_to_store_the_backup
|
||||||
|
|
||||||
###################################################################################
|
|
||||||
# JWT SECRET
|
|
||||||
#
|
|
||||||
# This JWT_SECRET is used to sign the authentication keys for user login
|
|
||||||
# You should set it to a long randomly generated value
|
|
||||||
# You can use this command to generate one: openssl rand -base64 128
|
|
||||||
###################################################################################
|
|
||||||
|
|
||||||
JWT_SECRET=
|
###################################################################################
|
||||||
|
# Typesense
|
||||||
|
###################################################################################
|
||||||
|
TYPESENSE_API_KEY=some-random-text
|
||||||
|
# TYPESENSE_ENABLED=false
|
||||||
|
|
||||||
###################################################################################
|
###################################################################################
|
||||||
# Reverse Geocoding
|
# Reverse Geocoding
|
||||||
@@ -76,3 +78,14 @@ PUBLIC_LOGIN_PAGE_MESSAGE=
|
|||||||
IMMICH_WEB_URL=http://immich-web:3000
|
IMMICH_WEB_URL=http://immich-web:3000
|
||||||
IMMICH_SERVER_URL=http://immich-server:3001
|
IMMICH_SERVER_URL=http://immich-server:3001
|
||||||
IMMICH_MACHINE_LEARNING_URL=http://immich-machine-learning:3003
|
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
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
sidebar_position: 6
|
sidebar_position: 7
|
||||||
---
|
---
|
||||||
|
|
||||||
# FAQ
|
# FAQ
|
||||||
@@ -14,15 +14,37 @@ sidebar_position: 6
|
|||||||
|
|
||||||
### How can I sync an existing directory with Immich's server?
|
### 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?
|
### 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.
|
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.
|
||||||
|
|
||||||
### What happens to existing files after I choose a new [Storage Template](/docs/features/storage-template.mdx)?
|
### Why does my uploaded photo show up with the wrong date or time in Immich?
|
||||||
|
|
||||||
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/features/jobs.md) page.
|
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?
|
### Why is object detection not very good?
|
||||||
|
|
||||||
@@ -38,11 +60,11 @@ Most Immich components are typically deployed using docker. To see logs for depl
|
|||||||
2. Set the corresponding `user` argument in `docker-compose` for each service.
|
2. Set the corresponding `user` argument in `docker-compose` for each service.
|
||||||
3. Add an additional volume to `immich-microservices` that mounts internally to `/usr/src/app/.reverse-geocoding-dump`.
|
3. Add an additional volume to `immich-microservices` that mounts internally to `/usr/src/app/.reverse-geocoding-dump`.
|
||||||
|
|
||||||
The non-root user/group needs will need read/write access to the volume mounts, including `UPLOAD_LOCATION`.
|
The non-root user/group needs read/write access to the volume mounts, including `UPLOAD_LOCATION`.
|
||||||
|
|
||||||
### How can I reset the admin password?
|
### How can I reset the admin password?
|
||||||
|
|
||||||
The admin password can be reset by running the [reset-admin-password](/docs/features/server-commands.md) command on the immich-server.
|
The admin password can be reset by running the [reset-admin-password](/docs/administration/server-commands.md) command on the immich-server.
|
||||||
|
|
||||||
### How can I **purge** data from Immich?
|
### How can I **purge** data from Immich?
|
||||||
|
|
||||||
|
|||||||
5
docs/docs/administration/_category_.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"label": "Administration",
|
||||||
|
"position": 4
|
||||||
|
}
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
BIN
docs/docs/administration/img/admin-jobs.png
Normal file
|
After Width: | Height: | Size: 111 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
BIN
docs/docs/administration/img/disable-password-login.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
docs/docs/administration/img/enable-password-login.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
docs/docs/administration/img/list-users.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
BIN
docs/docs/administration/img/reset-admin-password.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
9
docs/docs/administration/jobs.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# Jobs
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
:::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.
|
||||||
|
:::
|
||||||
@@ -14,19 +14,19 @@ To toggle the password login setting via the web, navigate to the "Administratio
|
|||||||
|
|
||||||
### Server Command
|
### Server Command
|
||||||
|
|
||||||
There are two [Server Commands](/docs/features/server-commands.md) for password login:
|
There are two [Server Commands](/docs/administration/server-commands.md) for password login:
|
||||||
|
|
||||||
1. `enable-password-login`
|
1. `enable-password-login`
|
||||||
2. `disable-password-login`
|
2. `disable-password-login`
|
||||||
|
|
||||||
See [Server Commands](/docs/features/server-commands.md) for more details about how to run them.
|
See [Server Commands](/docs/administration/server-commands.md) for more details about how to run them.
|
||||||
|
|
||||||
## Password Reset
|
## Password Reset
|
||||||
|
|
||||||
### Admin
|
### Admin
|
||||||
|
|
||||||
To reset the administrator password, use the `reset-admin-password` [Server Command](/docs/features/server-commands.md).
|
To reset the administrator password, use the `reset-admin-password` [Server Command](/docs/administration/server-commands.md).
|
||||||
|
|
||||||
### User
|
### User
|
||||||
|
|
||||||
Immich does not currently support self-service password reset. However, the administration can reset passwords for other users. See [User Management: Password Reset](/docs/features/user-management.mdx#password-reset) for more information about how to do this.
|
Immich does not currently support self-service password reset. However, the administration can reset passwords for other users. See [User Management: Password Reset](/docs/administration/user-management.mdx#password-reset) for more information about how to do this.
|
||||||
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.
|
||||||
33
docs/docs/administration/server-commands.md
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Server Commands
|
||||||
|
|
||||||
|
The `immich-server` docker image comes preinstalled with an administrative CLI (`immich`) that supports the following commands:
|
||||||
|
|
||||||
|
| Command | Description |
|
||||||
|
| ------------------------ | ------------------------------------- |
|
||||||
|
| `help` | Display help |
|
||||||
|
| `reset-admin-password` | Reset the password for the admin user |
|
||||||
|
| `disable-password-login` | Disable password login |
|
||||||
|
| `enable-password-login` | Enable password login |
|
||||||
|
| `list-users` | List Immich users |
|
||||||
|
|
||||||
|
## How to run a command
|
||||||
|
|
||||||
|
To run a command, [connect](/docs/guides/docker-help.md#attach-to-a-container) to the `immich_server` container and then execute the command via `immich <command>`.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
Reset Admin Password
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Disable Password Login
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Enabled Password Login
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
List Users
|
||||||
|
|
||||||
|

|
||||||
@@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"label": "Developer",
|
"label": "Developer",
|
||||||
"position": 4
|
"position": 5
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ Immich is a full-stack [TypeScript](https://www.typescriptlang.org/) application
|
|||||||
- [Nest.js](https://nestjs.com/)
|
- [Nest.js](https://nestjs.com/)
|
||||||
- [TypeORM](https://typeorm.io/) for database management.
|
- [TypeORM](https://typeorm.io/) for database management.
|
||||||
- [Jest](https://jestjs.io/) for testing.
|
- [Jest](https://jestjs.io/) for testing.
|
||||||
|
- [Python](https://www.python.org/) for Machine Learning.
|
||||||
|
|
||||||
### Database
|
### Database
|
||||||
|
|
||||||
|
|||||||
43
docs/docs/developer/contributing.md
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 3
|
||||||
|
---
|
||||||
|
|
||||||
|
# Contributing
|
||||||
|
|
||||||
|
Contributions are welcome!
|
||||||
|
|
||||||
|
## PR Checklist
|
||||||
|
|
||||||
|
When contributing code through a pull request, please check the following:
|
||||||
|
|
||||||
|
### Web Checks
|
||||||
|
|
||||||
|
- [ ] `npm run lint` (linting via ESLint)
|
||||||
|
- [ ] `npm run format` (formatting via Prettier)
|
||||||
|
- [ ] `npm run check` (Type checking via SvelteKit)
|
||||||
|
- [ ] `npm test` (Tests via Jest)
|
||||||
|
|
||||||
|
:::tip
|
||||||
|
Run all web checks with `npm run check:all`
|
||||||
|
:::
|
||||||
|
|
||||||
|
### Server Checks
|
||||||
|
|
||||||
|
- [ ] `npm run lint` (linting via ESLint)
|
||||||
|
- [ ] `npm run format` (formatting via Prettier)
|
||||||
|
- [ ] `npm run check` (Type checking via `tsc`)
|
||||||
|
- [ ] `npm test` (Tests via Jest)
|
||||||
|
|
||||||
|
:::tip
|
||||||
|
Run all server checks with `npm run check:all`
|
||||||
|
:::
|
||||||
|
|
||||||
|
### Open API
|
||||||
|
|
||||||
|
The Open API client libraries need to be regenerated whenever there are changes to the `immich-openapi-specs.json` file.
|
||||||
|
|
||||||
|
- [ ] `npm run api:generate`
|
||||||
|
|
||||||
|
:::tip
|
||||||
|
This can also be run via `make api` from the project root directory (not in the `server` folder)
|
||||||
|
:::
|
||||||
|
Before Width: | Height: | Size: 691 KiB After Width: | Height: | Size: 242 KiB |
@@ -23,8 +23,8 @@ All the services are packaged to run as with single Docker Compose command.
|
|||||||
### Instructions
|
### Instructions
|
||||||
|
|
||||||
1. Clone the project repo.
|
1. Clone the project repo.
|
||||||
2. Run `cp docker/.env.example docker/.env`.
|
2. Run `cp docker/example.env docker/.env`.
|
||||||
3. Edit `docker/.env` to provide values for the required variables `UPLOAD_LOCATION` and `JWT_SECRET`.
|
3. Edit `docker/.env` to provide values for the required variable `UPLOAD_LOCATION`.
|
||||||
4. From the root directory, run:
|
4. From the root directory, run:
|
||||||
|
|
||||||
```bash title="Start development server"
|
```bash title="Start development server"
|
||||||
@@ -99,7 +99,7 @@ After making any changes in the `server/libs/database/src/entities`, a database
|
|||||||
2. Run
|
2. Run
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run typeorm -- migration:generate ./libs/database/src/<migration-name> -d libs/database/src/config/database.config.ts
|
npm run typeorm -- migration:generate ./libs/infra/src/db/<migration-name> -d ./libs/infra/src/db/config/database.config.ts
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Check if the migration file makes sense.
|
3. Check if the migration file makes sense.
|
||||||
|
|||||||
@@ -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" />
|
<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
|
## 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.
|
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
|
||||||
|
|
||||||
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.
|
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
|
:::info Note
|
||||||
|
|
||||||
|
#### General
|
||||||
- The app must be in the background for the backup worker to start running.
|
- 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.
|
- 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
|
## 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 |
|
| Parameter | Description |
|
||||||
| ---------------- | ------------------------------------------------------------------- |
|
| ---------------- | ------------------------------------------------------------------- |
|
||||||
| --yes / -y | Assume yes on all interactive prompts |
|
| --yes / -y | Assume yes on all interactive prompts |
|
||||||
|
| --recursive / -r | Include subfolders |
|
||||||
| --delete / -da | Delete local assets after upload |
|
| --delete / -da | Delete local assets after upload |
|
||||||
| --key / -k | User's API key |
|
| --key / -k | User's API key |
|
||||||
| --server / -s | Immich's server address |
|
| --server / -s | Immich's server address |
|
||||||
| --directory / -d | Directory to upload from |
|
|
||||||
| --threads / -t | Number of threads to use (Default 5) |
|
| --threads / -t | Number of threads to use (Default 5) |
|
||||||
| --album/ -al | Create albums for assets based on the parent folder or a given name |
|
| --album/ -al | Create albums for assets based on the parent folder or a given name |
|
||||||
|
|
||||||
@@ -46,19 +52,37 @@ The API key can be obtained in the user setting panel on the web interface.
|
|||||||
|
|
||||||
### Run via Docker
|
### Run via Docker
|
||||||
|
|
||||||
Be aware that as this runs inside a container it mounts your current directory as a volume, and for the -d flag you need to use the path inside the container.
|
You can run the CLI inside of a docker container to avoid needing to install anything.
|
||||||
|
|
||||||
```bash
|
:::caution Running inside Docker
|
||||||
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 -d /import
|
Be aware that as this runs inside a container, you need to mount the folder from which you want to import into the container.
|
||||||
|
:::
|
||||||
|
|
||||||
|
```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
|
||||||
```
|
```
|
||||||
|
|
||||||
Optionally, you can create an alias:
|
```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
|
||||||
|
```
|
||||||
|
|
||||||
```bash
|
```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 -d /import
|
immich upload --key HFEJ38DNSDUEG --server http://192.168.1.216:2283/api
|
||||||
```
|
```
|
||||||
|
|
||||||
|
:::tip Internal networking
|
||||||
|
If you are running the CLI container on the same machine as your Immich server, you may not be able to reach the external address. In that case, try the following steps:
|
||||||
|
1. Find the internal Docker network used by Immich via `docker network ls`.
|
||||||
|
2. Adapt the above command to pass the `--network <immich_network>` argument to `docker run`, substituting `<immich_network>` with the result from step 1.
|
||||||
|
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/
|
||||||
|
```
|
||||||
|
:::
|
||||||
|
|
||||||
### Run from source
|
### Run from source
|
||||||
|
|
||||||
```bash title="Clone Repository"
|
```bash title="Clone Repository"
|
||||||
@@ -74,5 +98,5 @@ npm run build
|
|||||||
```
|
```
|
||||||
|
|
||||||
```bash title="Run the command"
|
```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 |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 16 KiB |
@@ -1,23 +0,0 @@
|
|||||||
# Jobs
|
|
||||||
|
|
||||||
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/features/storage-template.mdx), in order to apply the change to the existing library.
|
|
||||||
|
|
||||||

|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
# Server Commands
|
|
||||||
|
|
||||||
The `immich-server` docker image comes preinstalled with an administrative CLI (`immich`) that supports the following commands:
|
|
||||||
|
|
||||||
| Command | Description |
|
|
||||||
| ------------------------ | ------------------------------------- |
|
|
||||||
| `help` | Display help |
|
|
||||||
| `reset-admin-password` | Reset the password for the admin user |
|
|
||||||
| `disable-password-login` | Disable password login |
|
|
||||||
| `enable-password-login` | Enable password login |
|
|
||||||
|
|
||||||
## How to run a command
|
|
||||||
|
|
||||||
To run a command, connect to the container and then execute it by running `immich <command>`.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
```bash title="Reset Admin Password"
|
|
||||||
docker exec -it immich_server sh
|
|
||||||
|
|
||||||
/usr/src/app$ immich reset-admin-password
|
|
||||||
? Please choose a new password (optional) immich-is-awesome-unlike-this-password
|
|
||||||
New password:
|
|
||||||
immich-is-awesome-unlike-this-password
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash title="Disable Password Login"
|
|
||||||
docker exec -it immich_server sh
|
|
||||||
|
|
||||||
/usr/src/app$ immich disable-password-login
|
|
||||||
Password login has been disabled.
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash title="Enable Password Login"
|
|
||||||
docker exec -it immich_server sh
|
|
||||||
|
|
||||||
/usr/src/app$ immich enable-password-login
|
|
||||||
Password login has been enabled.
|
|
||||||
```
|
|
||||||
@@ -15,9 +15,9 @@ Users can change their own passwords.
|
|||||||

|

|
||||||
|
|
||||||
:::tip Reset Password
|
:::tip Reset Password
|
||||||
The admin can reset a password through the [User Management](/docs/features/user-management.mdx) screen.
|
The admin can reset a password through the [User Management](/docs/administration/user-management.mdx) screen.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
:::tip Reset Admin Password
|
:::tip Reset Admin Password
|
||||||
The admin password can be reset using a [Server Command](/docs/features/server-commands.md)
|
The admin password can be reset using a [Server Command](/docs/administration/server-commands.md)
|
||||||
:::
|
:::
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"label": "Guides",
|
"label": "Guides",
|
||||||
"position": 5
|
"position": 6
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,27 @@ sidebar_position: 1
|
|||||||
|
|
||||||
# Docker Help
|
# Docker Help
|
||||||
|
|
||||||
## Logs
|
## Containers
|
||||||
|
|
||||||
```bash title="Log Examples"
|
```bash
|
||||||
docker ps # see a list of running containers
|
docker ps # see a list of running containers
|
||||||
docker ps -a # see a list of running and stopped containers
|
docker ps -a # see a list of running and stopped containers
|
||||||
|
```
|
||||||
|
|
||||||
|
## Attach to a Container
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec -it <id or name> <command> # attach to a container with a command
|
||||||
|
docker exec -it immich_server sh
|
||||||
|
docker exec -it immich_microservices sh
|
||||||
|
docker exec -it immich_machine_learning sh
|
||||||
|
docker exec -it immich_web sh
|
||||||
|
docker exec -it immich_proxy sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Logs
|
||||||
|
|
||||||
|
```bash
|
||||||
docker logs <id or name> # see the logs for a specific container (by id or name)
|
docker logs <id or name> # see the logs for a specific container (by id or name)
|
||||||
|
|
||||||
docker logs immich_server
|
docker logs immich_server
|
||||||
|
|||||||
21
docs/docs/install/all-in-one.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 70
|
||||||
|
---
|
||||||
|
|
||||||
|
# All-In-One [Community]
|
||||||
|
|
||||||
|
:::note
|
||||||
|
This is a community contribution and not officially supported by the Immich team, but included here for convenience.
|
||||||
|
|
||||||
|
**Please report issues to the corresponding [Github Repository][github].**
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
For installation instructions, refer to the [Github Repository][github].
|
||||||
|
|
||||||
|
## Issues
|
||||||
|
|
||||||
|
For issues, open an issue on the associated [GitHub Repository][github].
|
||||||
|
|
||||||
|
[github]: https://github.com/imagegenius/docker-immich/
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
sidebar_position: 3
|
sidebar_position: 30
|
||||||
---
|
---
|
||||||
|
|
||||||
# Docker Compose [Recommended]
|
# Docker Compose [Recommended]
|
||||||
@@ -8,16 +8,16 @@ Docker Compose is the recommended method to run Immich in production. Below are
|
|||||||
|
|
||||||
### Step 1 - Download the required files
|
### Step 1 - Download the required files
|
||||||
|
|
||||||
Download [`docker-compose.yml`][compose-file] [`.env.example`][env-file].
|
Download [`docker-compose.yml`][compose-file] [`example.env`][env-file].
|
||||||
|
|
||||||
From a directory of your choice (e.g. `./immich-app`) run the following commands:
|
From a directory of your choice (e.g. `./immich-app`) run the following commands:
|
||||||
|
|
||||||
```bash title="Get docker-compose.yml file"
|
```bash title="Get docker-compose.yml file"
|
||||||
wget https://raw.githubusercontent.com/immich-app/immich/main/docker/docker-compose.yml
|
wget https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash title="Get .env file"
|
```bash title="Get .env file"
|
||||||
wget -O .env https://raw.githubusercontent.com/immich-app/immich/main/docker/.env.example
|
wget -O .env https://github.com/immich-app/immich/releases/latest/download/example.env
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 2 - Populate the .env file with custom values
|
### Step 2 - Populate the .env file with custom values
|
||||||
@@ -46,6 +46,11 @@ DB_DATABASE_NAME=immich
|
|||||||
REDIS_HOSTNAME=immich_redis
|
REDIS_HOSTNAME=immich_redis
|
||||||
|
|
||||||
# Optional Redis settings:
|
# 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_PORT=6379
|
||||||
# REDIS_DBINDEX=0
|
# REDIS_DBINDEX=0
|
||||||
# REDIS_PASSWORD=
|
# REDIS_PASSWORD=
|
||||||
@@ -63,15 +68,6 @@ UPLOAD_LOCATION=absolute_location_on_your_machine_where_you_want_to_store_the_ba
|
|||||||
|
|
||||||
LOG_LEVEL=simple
|
LOG_LEVEL=simple
|
||||||
|
|
||||||
###################################################################################
|
|
||||||
# JWT SECRET
|
|
||||||
###################################################################################
|
|
||||||
|
|
||||||
# This JWT_SECRET is used to sign the authentication keys for user login
|
|
||||||
# You should set it to a long randomly generated value
|
|
||||||
# You can use this command to generate one: openssl rand -base64 128
|
|
||||||
JWT_SECRET=
|
|
||||||
|
|
||||||
###################################################################################
|
###################################################################################
|
||||||
# Reverse Geocoding
|
# Reverse Geocoding
|
||||||
####################################################################################
|
####################################################################################
|
||||||
@@ -102,11 +98,6 @@ PUBLIC_LOGIN_PAGE_MESSAGE="My Family Photos and Videos Backup Server"
|
|||||||
|
|
||||||
- Populate custom database information if necessary.
|
- Populate custom database information if necessary.
|
||||||
- Populate `UPLOAD_LOCATION` with your preferred location for storing backup assets.
|
- Populate `UPLOAD_LOCATION` with your preferred location for storing backup assets.
|
||||||
- Populate a secret value for `JWT_SECRET`. You can use the command below to generate a secure key:
|
|
||||||
|
|
||||||
```bash title="Command to generate secure JWT_SECRET key"
|
|
||||||
openssl rand -base64 128
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 3 - Start the containers
|
### Step 3 - Start the containers
|
||||||
|
|
||||||
@@ -126,5 +117,10 @@ When a new version of Immich is [released](https://github.com/immich-app/immich/
|
|||||||
docker-compose pull && docker-compose up -d # Or `docker compose`
|
docker-compose pull && docker-compose up -d # Or `docker compose`
|
||||||
```
|
```
|
||||||
|
|
||||||
[compose-file]: https://raw.githubusercontent.com/immich-app/immich/main/docker/docker-compose.yml
|
:::caution Automatic Updates
|
||||||
[env-file]: https://raw.githubusercontent.com/immich-app/immich/main/docker/.env.example
|
Immich is currently under heavy development, which means you can expect breaking changes and bugs. Therefore, we recommend reading the release notes prior to updating and to take special care when using automated tools like [Watchtower][watchtower].
|
||||||
|
:::
|
||||||
|
|
||||||
|
[compose-file]: https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
|
||||||
|
[env-file]: https://github.com/immich-app/immich/releases/latest/download/example.env
|
||||||
|
[watchtower]: https://containrrr.dev/watchtower/
|
||||||
|
|||||||
24
docs/docs/install/kubernetes.md
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
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).
|
||||||
|
|
||||||
|
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
|
||||||
|
nodes have a search domain set, like:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cat /etc/resolv.conf
|
||||||
|
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
|
||||||
|
`resolv.conf`, or set the `DISABLE_REVERSE_GEOCODING` environment variable for Immich to `true` to disable the geocoder.
|
||||||
|
:::
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
sidebar_position: 4
|
sidebar_position: 50
|
||||||
---
|
---
|
||||||
|
|
||||||
# Portainer
|
# Portainer
|
||||||
@@ -9,7 +9,7 @@ Install Immich using Portainer's Stack feature.
|
|||||||
1. Go to "**Stacks**" in the left sidebar.
|
1. Go to "**Stacks**" in the left sidebar.
|
||||||
2. Click on "**Add stack**".
|
2. Click on "**Add stack**".
|
||||||
3. Give the stack a name (i.e. Immich), and select "**Web Editor**" as the build method.
|
3. Give the stack a name (i.e. Immich), and select "**Web Editor**" as the build method.
|
||||||
4. Copy the content of the `docker-compose.yml` file from the [GitHub repository](https://raw.githubusercontent.com/immich-app/immich/main/docker/docker-compose.yml).
|
4. Copy the content of the `docker-compose.yml` file from the [GitHub repository](https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml).
|
||||||
5. Replace `.env` with `stack.env` for all containers that need to use environment variables in the web editor.
|
5. Replace `.env` with `stack.env` for all containers that need to use environment variables in the web editor.
|
||||||
|
|
||||||
<img
|
<img
|
||||||
@@ -28,7 +28,7 @@ Install Immich using Portainer's Stack feature.
|
|||||||
alt="Dot Env Example"
|
alt="Dot Env Example"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
9. Copy the content of the `.env.example` file from the [GitHub repository](https://raw.githubusercontent.com/immich-app/immich/main/docker/.env.example) and paste into the editor.
|
9. Copy the content of the `example.env` file from the [GitHub repository](https://github.com/immich-app/immich/releases/latest/download/example.env) and paste into the editor.
|
||||||
10. Switch back to "**Simple Mode**".
|
10. Switch back to "**Simple Mode**".
|
||||||
|
|
||||||
<img
|
<img
|
||||||
@@ -40,11 +40,6 @@ Install Immich using Portainer's Stack feature.
|
|||||||
|
|
||||||
* Populate custom database information if necessary.
|
* Populate custom database information if necessary.
|
||||||
* Populate `UPLOAD_LOCATION` with your preferred location for storing backup assets.
|
* Populate `UPLOAD_LOCATION` with your preferred location for storing backup assets.
|
||||||
* Populate a secret value for `JWT_SECRET`. You can use the command below to generate a secure key:
|
|
||||||
|
|
||||||
```bash title="Generate secure JWT_SECRET key"
|
|
||||||
openssl rand -base64 128
|
|
||||||
```
|
|
||||||
|
|
||||||
11. Click on "**Deploy the stack**".
|
11. Click on "**Deploy the stack**".
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
sidebar_position: 1
|
sidebar_position: 10
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
@@ -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/)
|
- **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.
|
- **RAM**: At least 2GB, preferred 4GB.
|
||||||
- **CPU**: At least 2 cores, preferred 4 cores.
|
- **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.
|
|
||||||
:::
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
sidebar_position: 2
|
sidebar_position: 20
|
||||||
---
|
---
|
||||||
|
|
||||||
# Install Script [Experimental]
|
# Install Script [Experimental]
|
||||||
@@ -16,7 +16,7 @@ curl -o- https://raw.githubusercontent.com/immich-app/immich/main/install.sh | b
|
|||||||
|
|
||||||
The script will perform the following actions:
|
The script will perform the following actions:
|
||||||
|
|
||||||
1. Download [docker-compose.yml](https://github.com/immich-app/immich/blob/main/docker/docker-compose.yml), and the [.env](https://github.com/immich-app/immich/blob/main/docker/.env.example) file from the main branch of the [repository](https://github.com/immich-app/immich).
|
1. Download [docker-compose.yml](https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml), and the [.env](https://github.com/immich-app/immich/releases/latest/download/example.env) file from the main branch of the [repository](https://github.com/immich-app/immich).
|
||||||
2. Populate the `.env` file with necessary information based on the current directory path.
|
2. Populate the `.env` file with necessary information based on the current directory path.
|
||||||
3. Start the containers.
|
3. Start the containers.
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,28 @@
|
|||||||
---
|
---
|
||||||
sidebar_position: 5
|
sidebar_position: 60
|
||||||
---
|
---
|
||||||
|
|
||||||
# Unraid
|
# Unraid
|
||||||
|
|
||||||
Immich can easily be installed and updated on Unraid using the [Docker Compose Manager](https://forums.unraid.net/topic/114415-plugin-docker-compose-manager/) plugin from the Unraid Community Apps.
|
Immich can easily be installed and updated on Unraid via:
|
||||||
|
1. [Docker Compose Manager](https://forums.unraid.net/topic/114415-plugin-docker-compose-manager/) plugin from the Unraid Community Apps
|
||||||
|
2. Community made template on the Unraid Community Apps
|
||||||
|
|
||||||
|
## Community Applications Template
|
||||||
|
|
||||||
|
:::info
|
||||||
|
|
||||||
|
- The Unraid template uses a community made image and is not officially supported by Immich
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
For more information about setting up the community image see [here](https://github.com/imagegenius/docker-immich#application-setup)
|
||||||
|
|
||||||
|
## Docker-Compose Method (Official)
|
||||||
|
|
||||||
:::info
|
:::info
|
||||||
|
|
||||||
@@ -27,7 +45,7 @@ alt="Select Plugins > Compose.Manager > Add New Stack > Label it Immich"
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
3. Select the cog ⚙️ next to Immich then click "**Edit Stack**"
|
3. Select the cog ⚙️ next to Immich then click "**Edit Stack**"
|
||||||
4. Click "**Compose File**" and then paste the entire contents of the [Immich Docker Compose](https://raw.githubusercontent.com/immich-app/immich/main/docker/docker-compose.yml) file into the Unraid editor
|
4. Click "**Compose File**" and then paste the entire contents of the [Immich Docker Compose](https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml) file into the Unraid editor
|
||||||
<details >
|
<details >
|
||||||
<summary>Using an existing Postgres container? Click me! Otherwise proceed to step 5.</summary>
|
<summary>Using an existing Postgres container? Click me! Otherwise proceed to step 5.</summary>
|
||||||
<ul>
|
<ul>
|
||||||
@@ -53,9 +71,8 @@ alt="Select Plugins > Compose.Manager > Add New Stack > Label it Immich"
|
|||||||
</details>
|
</details>
|
||||||
5. Click "**Save Changes**", you will be promoted to edit stack UI labels, just leave this blank and click "**Ok**"
|
5. Click "**Save Changes**", you will be promoted to edit stack UI labels, just leave this blank and click "**Ok**"
|
||||||
6. Select the cog ⚙️ next to Immich, click "**Edit Stack**", then click "**Env File**"
|
6. Select the cog ⚙️ next to Immich, click "**Edit Stack**", then click "**Env File**"
|
||||||
7. Past the entire contents of the [Immich .env.example](https://raw.githubusercontent.com/immich-app/immich/main/docker/.env.example) 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:
|
||||||
|
|
||||||
- `JWT_SECRET`: Generate a unique secret and paste the value here > Can be generated by either typing `openssl rand -base64 128` in your terminal or copying from [uuidgenerator](https://www.uuidgenerator.net/version1)
|
|
||||||
- `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`
|
- `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`
|
||||||
|
|
||||||
<img
|
<img
|
||||||
@@ -126,8 +143,8 @@ alt="Immich update notification"
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
1. Go to the "**Docker**" tab and scroll to the Compose section
|
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
|
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 unecessary.
|
> Note: **Do not** select Compose Down first, it is unnecessary.
|
||||||
3. Once complete you will see a "_Connection Closed_" message, select "**Done**".
|
3. Once complete you will see a "_Connection Closed_" message, select "**Done**".
|
||||||
<img
|
<img
|
||||||
src={require('./img/unraid11.png').default}
|
src={require('./img/unraid11.png').default}
|
||||||
|
|||||||
@@ -14,6 +14,10 @@ If you feel like this is the right cause and the app is something you see yourse
|
|||||||
|
|
||||||
- Monthly donation via [GitHub Sponsors](https://github.com/sponsors/alextran1502)
|
- Monthly donation via [GitHub Sponsors](https://github.com/sponsors/alextran1502)
|
||||||
- One-time donation via [GitHub Sponsors](https://github.com/sponsors/alextran1502?frequency=one-time&sponsor=alextran1502)
|
- One-time donation via [GitHub Sponsors](https://github.com/sponsors/alextran1502?frequency=one-time&sponsor=alextran1502)
|
||||||
|
- [Librepay](https://liberapay.com/alex.tran1502/)
|
||||||
|
- [buymeacoffee](https://www.buymeacoffee.com/altran1502)
|
||||||
|
- Bitcoin: 1FvEp6P6NM8EZEkpGUFAN2LqJ1gxusNxZX
|
||||||
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 52 KiB |
@@ -15,7 +15,7 @@ function HomepageHeader() {
|
|||||||
<p>ON MOBILE DEVICE</p>
|
<p>ON MOBILE DEVICE</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex place-items-center place-content-center mt-9 mb-16 gap-4 ">
|
<div className="flex flex-col sm:flex-row place-items-center place-content-center mt-9 mb-16 gap-4 ">
|
||||||
<Link
|
<Link
|
||||||
className="flex place-items-center place-content-center py-3 px-8 border bg-immich-primary dark:bg-immich-dark-primary rounded-full no-underline hover:no-underline text-white hover:text-gray-50 dark:text-immich-dark-bg font-bold"
|
className="flex place-items-center place-content-center py-3 px-8 border bg-immich-primary dark:bg-immich-dark-primary rounded-full no-underline hover:no-underline text-white hover:text-gray-50 dark:text-immich-dark-bg font-bold"
|
||||||
to="docs/overview/introduction"
|
to="docs/overview/introduction"
|
||||||
|
|||||||
@@ -13,9 +13,15 @@
|
|||||||
{ "source": "/docs/overview/technology-stack", "destination": "/docs/developer/architecture" },
|
{ "source": "/docs/overview/technology-stack", "destination": "/docs/developer/architecture" },
|
||||||
{ "source": "/docs/usage/automatic-backup", "destination": "/docs/features/automatic-backup" },
|
{ "source": "/docs/usage/automatic-backup", "destination": "/docs/features/automatic-backup" },
|
||||||
{ "source": "/docs/usage/bulk-upload", "destination": "/docs/features/bulk-upload" },
|
{ "source": "/docs/usage/bulk-upload", "destination": "/docs/features/bulk-upload" },
|
||||||
{ "source": "/docs/usage/oauth", "destination": "/docs/features/oauth" },
|
{ "source": "/docs/usage/oauth", "destination": "/docs/administration/oauth" },
|
||||||
{ "source": "/docs/usage/post-installation", "destination": "/docs/install/post-install" },
|
{ "source": "/docs/usage/post-installation", "destination": "/docs/install/post-install" },
|
||||||
{ "source": "/docs/usage/update", "destination": "/docs/install/docker-compose#step-4---upgrading" },
|
{ "source": "/docs/usage/update", "destination": "/docs/install/docker-compose#step-4---upgrading" },
|
||||||
{ "source": "/docs/usage/server-commands", "destination": "/docs/features/server-commands" }
|
{ "source": "/docs/usage/server-commands", "destination": "/docs/administration/server-commands" },
|
||||||
|
{ "source": "/docs/features/jobs", "destination": "/docs/administration/jobs" },
|
||||||
|
{ "source": "/docs/features/oauth", "destination": "/docs/administration/oauth" },
|
||||||
|
{ "source": "/docs/features/password-login", "destination": "/docs/administration/password-login" },
|
||||||
|
{ "source": "/docs/features/server-commands", "destination": "/docs/administration/server-commands" },
|
||||||
|
{ "source": "/docs/features/storage-template", "destination": "/docs/administration/storage-template" },
|
||||||
|
{ "source": "/docs/features/user-management", "destination": "/docs/administration/user-management" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ download_docker_compose_file() {
|
|||||||
|
|
||||||
download_dot_env_file() {
|
download_dot_env_file() {
|
||||||
echo "Downloading .env file..."
|
echo "Downloading .env file..."
|
||||||
curl -L https://raw.githubusercontent.com/immich-app/immich/$release_version/docker/.env.example -o ./.env >/dev/null 2>&1
|
curl -L https://raw.githubusercontent.com/immich-app/immich/$release_version/docker/example.env -o ./.env >/dev/null 2>&1
|
||||||
}
|
}
|
||||||
|
|
||||||
replace_env_value() {
|
replace_env_value() {
|
||||||
@@ -45,12 +45,6 @@ populate_upload_location() {
|
|||||||
replace_env_value "UPLOAD_LOCATION" $upload_location
|
replace_env_value "UPLOAD_LOCATION" $upload_location
|
||||||
}
|
}
|
||||||
|
|
||||||
generate_jwt_secret() {
|
|
||||||
echo "Generating JWT_SECRET value..."
|
|
||||||
jwt_secret=$(openssl rand -base64 128)
|
|
||||||
replace_env_value "JWT_SECRET" $jwt_secret
|
|
||||||
}
|
|
||||||
|
|
||||||
start_docker_compose() {
|
start_docker_compose() {
|
||||||
echo "Starting Immich's docker containers"
|
echo "Starting Immich's docker containers"
|
||||||
|
|
||||||
@@ -92,5 +86,4 @@ create_immich_directory
|
|||||||
download_docker_compose_file
|
download_docker_compose_file
|
||||||
download_dot_env_file
|
download_dot_env_file
|
||||||
populate_upload_location
|
populate_upload_location
|
||||||
generate_jwt_secret
|
|
||||||
start_docker_compose
|
start_docker_compose
|
||||||
|
|||||||
@@ -34,3 +34,15 @@ download:
|
|||||||
locale_code: pt-BR
|
locale_code: pt-BR
|
||||||
- file: mobile/assets/i18n/pl-PL.json
|
- file: mobile/assets/i18n/pl-PL.json
|
||||||
locale_code: pl-PL
|
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/no-NO.json
|
||||||
|
locale_code: no-NO
|
||||||
|
|||||||
@@ -1,4 +1 @@
|
|||||||
node_modules/
|
venv/
|
||||||
upload/
|
|
||||||
dist/
|
|
||||||
|
|
||||||
@@ -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',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
41
machine-learning/.gitignore
vendored
@@ -1,37 +1,4 @@
|
|||||||
# compiled output
|
upload/
|
||||||
/dist
|
venv/
|
||||||
/node_modules
|
__pycache__/
|
||||||
|
model-cache/
|
||||||
# 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/
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"singleQuote": true,
|
|
||||||
"trailingComma": "all"
|
|
||||||
}
|
|
||||||
@@ -1,42 +1,25 @@
|
|||||||
|
FROM python:3.10 as builder
|
||||||
|
|
||||||
FROM node:16-bullseye-slim as builder
|
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||||
|
PYTHONUNBUFFERED=1 \
|
||||||
|
PIP_NO_CACHE_DIR=true
|
||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
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
|
||||||
|
|
||||||
|
COPY --from=builder /opt/venv /opt/venv
|
||||||
|
|
||||||
|
ENV TRANSFORMERS_CACHE=/cache \
|
||||||
|
PYTHONDONTWRITEBYTECODE=1 \
|
||||||
|
PYTHONUNBUFFERED=1 \
|
||||||
|
PATH="/opt/venv/bin:$PATH"
|
||||||
|
|
||||||
WORKDIR /usr/src/app
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
RUN apt-get update
|
|
||||||
RUN apt-get install gcc g++ make cmake python3 python3-pip ffmpeg -y
|
|
||||||
|
|
||||||
COPY package.json package-lock.json ./
|
|
||||||
|
|
||||||
RUN npm ci
|
|
||||||
RUN npm rebuild @tensorflow/tfjs-node --build-from-source
|
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
|
CMD ["gunicorn", "src.main:server"]
|
||||||
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
|
|
||||||
|
|
||||||
RUN apt-get update \
|
|
||||||
&& apt-get install -y ffmpeg \
|
|
||||||
&& rm -rf /var/cache/apt/lists
|
|
||||||
|
|
||||||
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" ]
|
|
||||||
|
|||||||
@@ -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"
|
|
||||||
}
|
|
||||||
16249
machine-learning/package-lock.json
generated
@@ -1,80 +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",
|
|
||||||
"@nestjs/mapped-types": "^1.0.1",
|
|
||||||
"@nestjs/platform-express": "^8.0.0",
|
|
||||||
"@tensorflow-models/coco-ssd": "^2.2.2",
|
|
||||||
"@tensorflow-models/mobilenet": "^2.1.0",
|
|
||||||
"@tensorflow/tfjs": "^3.19.0",
|
|
||||||
"@tensorflow/tfjs-converter": "^3.19.0",
|
|
||||||
"@tensorflow/tfjs-core": "^3.19.0",
|
|
||||||
"@tensorflow/tfjs-node": "^3.19.0",
|
|
||||||
"@tensorflow/tfjs-node-gpu": "^3.19.0",
|
|
||||||
"@trpc/server": "^9.20.3",
|
|
||||||
"reflect-metadata": "^0.1.13",
|
|
||||||
"rimraf": "^3.0.2",
|
|
||||||
"rxjs": "^7.2.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",
|
|
||||||
"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,25 +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);
|
|
||||||
|
|
||||||
await app.listen(3003, () => {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||