mirror of
https://github.com/photoprism/photoprism.git
synced 2025-09-26 21:01:58 +08:00
Compare commits
963 Commits
scratch/fr
...
d447adc59c
Author | SHA1 | Date | |
---|---|---|---|
![]() |
d447adc59c | ||
![]() |
41da164469 | ||
![]() |
29ca2c1331 | ||
![]() |
2fe48605a2 | ||
![]() |
75af48c0c0 | ||
![]() |
13e1c751d4 | ||
![]() |
f6f4b85e66 | ||
![]() |
eee1b3fbfc | ||
![]() |
ce2d793a48 | ||
![]() |
83a12fb58b | ||
![]() |
1315df8c1f | ||
![]() |
c9e6b7c22b | ||
![]() |
518079450e | ||
![]() |
aa5368e00a | ||
![]() |
1c3009d9b5 | ||
![]() |
2818a9e6a8 | ||
![]() |
464a64339f | ||
![]() |
b40e4c5597 | ||
![]() |
887a39e7d9 | ||
![]() |
2a116cffb3 | ||
![]() |
1f10dcaf85 | ||
![]() |
202d513019 | ||
![]() |
e221a8ee73 | ||
![]() |
fb27969e30 | ||
![]() |
4a7c355d28 | ||
![]() |
c7380111b2 | ||
![]() |
40a4dbfe26 | ||
![]() |
1ab4c32ee8 | ||
![]() |
19b09ebf0b | ||
![]() |
00088d66cd | ||
![]() |
e04df34453 | ||
![]() |
e1d031bea7 | ||
![]() |
ec8ea96f31 | ||
![]() |
b3fec4a2f5 | ||
![]() |
0ce82056ca | ||
![]() |
dbf1650c1c | ||
![]() |
5db044284b | ||
![]() |
3c821a3ea7 | ||
![]() |
5a4e03eff0 | ||
![]() |
a4cd1ac1fd | ||
![]() |
ea8d413deb | ||
![]() |
b5c9e9f160 | ||
![]() |
d3775f02e6 | ||
![]() |
efbcf34588 | ||
![]() |
ced562dfb3 | ||
![]() |
e639c962d7 | ||
![]() |
efd55b50d9 | ||
![]() |
8de7fa35af | ||
![]() |
970a0a190e | ||
![]() |
f0b9faac8b | ||
![]() |
023fbe3a1d | ||
![]() |
3f11165f61 | ||
![]() |
c36e66c847 | ||
![]() |
dbf0fa6c25 | ||
![]() |
4ea628af5c | ||
![]() |
cd81094d25 | ||
![]() |
11c7d9f7af | ||
![]() |
64da1d36ed | ||
![]() |
e45a23f9a4 | ||
![]() |
cc93144bcb | ||
![]() |
7ff62e0194 | ||
![]() |
ce6546c635 | ||
![]() |
b894079f62 | ||
![]() |
7bed1cd46a | ||
![]() |
886794874d | ||
![]() |
55755f6ede | ||
![]() |
acdf91d668 | ||
![]() |
f84bfbefaa | ||
![]() |
9d79f448bd | ||
![]() |
3f519b7a87 | ||
![]() |
cdbd6a9fb6 | ||
![]() |
aaf222e29b | ||
![]() |
29dcf7070c | ||
![]() |
9bb323f965 | ||
![]() |
0d572032a9 | ||
![]() |
68d387778e | ||
![]() |
71f5bab407 | ||
![]() |
08616ae426 | ||
![]() |
5ee5974188 | ||
![]() |
ea5dd3c002 | ||
![]() |
28b9c39f1b | ||
![]() |
f948cd4efb | ||
![]() |
a806ef8d71 | ||
![]() |
c27052a735 | ||
![]() |
4f3b694164 | ||
![]() |
634445fb97 | ||
![]() |
6cdca39fad | ||
![]() |
6a57daffb4 | ||
![]() |
13730174fe | ||
![]() |
632cc1f425 | ||
![]() |
f0df9d2c88 | ||
![]() |
5afc09ecaf | ||
![]() |
cc0661eff6 | ||
![]() |
a6f66127fb | ||
![]() |
7d3978cfd4 | ||
![]() |
e7d4bc509d | ||
![]() |
d44b85a0df | ||
![]() |
b0c3572432 | ||
![]() |
cb9ada8478 | ||
![]() |
95c6743b2c | ||
![]() |
22863b8b0f | ||
![]() |
351c3688b8 | ||
![]() |
95ac440d28 | ||
![]() |
2e3d187938 | ||
![]() |
e7e49c3644 | ||
![]() |
f2ec047c85 | ||
![]() |
9545cd8a3e | ||
![]() |
34c66ebfdd | ||
![]() |
22d7e65f3f | ||
![]() |
f5a4aacc5c | ||
![]() |
c36bb566af | ||
![]() |
a88580af7c | ||
![]() |
9ea676c7e5 | ||
![]() |
2dc82bfa48 | ||
![]() |
ff2c3b9559 | ||
![]() |
a0b44b2ca2 | ||
![]() |
c3537b10e5 | ||
![]() |
aa6c62abcb | ||
![]() |
19fff8b0bf | ||
![]() |
fccdc50e6e | ||
![]() |
7de8ee88d8 | ||
![]() |
2c17b21569 | ||
![]() |
09e8a15a7f | ||
![]() |
6c61eb5010 | ||
![]() |
6766cc330d | ||
![]() |
b887ef9aed | ||
![]() |
de4b8b9539 | ||
![]() |
8241f1c559 | ||
![]() |
fd6216ad3a | ||
![]() |
a8dd73737f | ||
![]() |
619949ffc1 | ||
![]() |
0357bc9abd | ||
![]() |
68590ab408 | ||
![]() |
27d6834a22 | ||
![]() |
1b437c38f4 | ||
![]() |
5b61fe3782 | ||
![]() |
7bebf3bd60 | ||
![]() |
0823dceab1 | ||
![]() |
8337eb268c | ||
![]() |
b1eda7abe1 | ||
![]() |
cfe1bf62fd | ||
![]() |
45e998d941 | ||
![]() |
0cb4acbc20 | ||
![]() |
a1ea21161b | ||
![]() |
e9fca94656 | ||
![]() |
2e15e1868f | ||
![]() |
9980cf5bdc | ||
![]() |
6e50ef0135 | ||
![]() |
09ce6c77de | ||
![]() |
16dc286976 | ||
![]() |
46683a155c | ||
![]() |
7470924a84 | ||
![]() |
8a976825bf | ||
![]() |
e80c1e1df7 | ||
![]() |
c7e71bbbe2 | ||
![]() |
37908ca3b5 | ||
![]() |
2a8e991550 | ||
![]() |
a55a4f8ae4 | ||
![]() |
eba9e89380 | ||
![]() |
589ed92904 | ||
![]() |
41804a262b | ||
![]() |
597593f4ee | ||
![]() |
e3e034cc68 | ||
![]() |
0bce60c046 | ||
![]() |
13177b0c32 | ||
![]() |
af7983b77c | ||
![]() |
4da369d8b8 | ||
![]() |
519a6ab34a | ||
![]() |
2a7351ee9a | ||
![]() |
ff00681137 | ||
![]() |
21c8b18bf0 | ||
![]() |
a7a41fe000 | ||
![]() |
d47b38bc8b | ||
![]() |
52204ee246 | ||
![]() |
3d4e2bde49 | ||
![]() |
05a550aa8a | ||
![]() |
f55a7190fc | ||
![]() |
0f999703c3 | ||
![]() |
db3a2b0309 | ||
![]() |
39be3d7122 | ||
![]() |
db22069997 | ||
![]() |
745a0a3661 | ||
![]() |
242083080d | ||
![]() |
e7db7efc58 | ||
![]() |
dbfe4e5dc1 | ||
![]() |
a890f8da16 | ||
![]() |
c22c5c0151 | ||
![]() |
6655a66e8f | ||
![]() |
875880110b | ||
![]() |
ab0bd1c732 | ||
![]() |
2b48fe20dd | ||
![]() |
ca8490d048 | ||
![]() |
2b9a3c9924 | ||
![]() |
3c84771c01 | ||
![]() |
a6d840056c | ||
![]() |
0d24ec5abb | ||
![]() |
fb6d920b1b | ||
![]() |
9c7c6c3d27 | ||
![]() |
16ac7a9d11 | ||
![]() |
9388cb7f66 | ||
![]() |
29c70cb0a9 | ||
![]() |
6a20ca45b5 | ||
![]() |
34065a6bf8 | ||
![]() |
b241fa621d | ||
![]() |
b7dc81fe29 | ||
![]() |
f83d77e40a | ||
![]() |
3177a61f75 | ||
![]() |
523605f7d7 | ||
![]() |
10fe7d2b40 | ||
![]() |
75785ff2f3 | ||
![]() |
f6c922be00 | ||
![]() |
a80bdf065f | ||
![]() |
977d06b560 | ||
![]() |
c2b4af2a3a | ||
![]() |
fd3f6311d4 | ||
![]() |
5246677ffa | ||
![]() |
6e955523b6 | ||
![]() |
1bd9bb9d0c | ||
![]() |
98e9daf687 | ||
![]() |
31901ff2e3 | ||
![]() |
e5dcf23f0c | ||
![]() |
0f5b774b06 | ||
![]() |
34b71f800e | ||
![]() |
2df90b45fa | ||
![]() |
8ea7494456 | ||
![]() |
96137a849a | ||
![]() |
aeba5bfc4c | ||
![]() |
eef76ded5f | ||
![]() |
b4ac12c301 | ||
![]() |
38cafb1c2b | ||
![]() |
3b1e1bb32a | ||
![]() |
e704ccfc47 | ||
![]() |
fe7af9ec91 | ||
![]() |
8149d4c63a | ||
![]() |
fce72f01a2 | ||
![]() |
d622c4d214 | ||
![]() |
468080ec6d | ||
![]() |
4c24973a24 | ||
![]() |
9d5a5d848a | ||
![]() |
5a7c5613b1 | ||
![]() |
4b5e3b574a | ||
![]() |
99159f072a | ||
![]() |
f0939094fc | ||
![]() |
a851e325dd | ||
![]() |
0ff2d0df5e | ||
![]() |
f6d9ff8e43 | ||
![]() |
f1a33a5516 | ||
![]() |
3dcc33260e | ||
![]() |
7dd870fcf1 | ||
![]() |
1afc7d955a | ||
![]() |
b2d36b395b | ||
![]() |
3448d1a635 | ||
![]() |
02ab8caef1 | ||
![]() |
da86263390 | ||
![]() |
ae42af54d8 | ||
![]() |
f67ba0e634 | ||
![]() |
1912f17aaf | ||
![]() |
6a803a8614 | ||
![]() |
57f4e39b33 | ||
![]() |
aa533ff7ef | ||
![]() |
3ff0a30469 | ||
![]() |
6cccef7ae8 | ||
![]() |
c6f7a6f373 | ||
![]() |
ddd343d528 | ||
![]() |
c05fe19ba9 | ||
![]() |
b608eae3e5 | ||
![]() |
df61612d73 | ||
![]() |
f7f403fef7 | ||
![]() |
1c5cea7683 | ||
![]() |
2a7e06e35f | ||
![]() |
adc4dc0f74 | ||
![]() |
4bc9cd6ca2 | ||
![]() |
eb8d2062a5 | ||
![]() |
4e6e0d287b | ||
![]() |
546635f8b6 | ||
![]() |
ff229e1bd0 | ||
![]() |
e029a64632 | ||
![]() |
e2763c4aee | ||
![]() |
e24d8f532a | ||
![]() |
2ad1466e06 | ||
![]() |
a571a228e6 | ||
![]() |
f7a6b0fa6c | ||
![]() |
88126e3e48 | ||
![]() |
66cd55461f | ||
![]() |
65b8503f63 | ||
![]() |
6e859ceecb | ||
![]() |
2b4234da00 | ||
![]() |
28873182be | ||
![]() |
a910795525 | ||
![]() |
d5816e0f9f | ||
![]() |
f1cfe8d406 | ||
![]() |
aca000854c | ||
![]() |
312f8e10be | ||
![]() |
1fa7b455a1 | ||
![]() |
86401086ba | ||
![]() |
342519a518 | ||
![]() |
ad653db969 | ||
![]() |
675c2a3f95 | ||
![]() |
78f5a48b0b | ||
![]() |
e6a1b54547 | ||
![]() |
287b921d4f | ||
![]() |
31614697a2 | ||
![]() |
2229ee32fb | ||
![]() |
41dc0febba | ||
![]() |
50c345f0ad | ||
![]() |
38da638f88 | ||
![]() |
6bfbad40af | ||
![]() |
02ef7dbdee | ||
![]() |
845813d642 | ||
![]() |
f99fee1fe7 | ||
![]() |
ee443c066b | ||
![]() |
02109cf4e6 | ||
![]() |
38e331a48d | ||
![]() |
61683015f2 | ||
![]() |
9ad5a533af | ||
![]() |
2481de49c4 | ||
![]() |
004feeb708 | ||
![]() |
d28b3101e0 | ||
![]() |
8fcc2a232b | ||
![]() |
5ad7f6318b | ||
![]() |
cedc8799d3 | ||
![]() |
5860b01248 | ||
![]() |
f80ac62e6b | ||
![]() |
57349bdb99 | ||
![]() |
0fc3ec8183 | ||
![]() |
b582133df7 | ||
![]() |
037c0351d9 | ||
![]() |
ff6151f84a | ||
![]() |
3ff0ec01be | ||
![]() |
595b116ae6 | ||
![]() |
73374cb325 | ||
![]() |
77ac3b545f | ||
![]() |
c49ba11288 | ||
![]() |
395ee8426e | ||
![]() |
d43ec9492a | ||
![]() |
20a82df0e8 | ||
![]() |
55704fea58 | ||
![]() |
02d8525ade | ||
![]() |
4b1cc5d424 | ||
![]() |
829611c37f | ||
![]() |
cb208bc09f | ||
![]() |
24b7b03f7b | ||
![]() |
1b4b478067 | ||
![]() |
76f6f2d52f | ||
![]() |
5b152ac542 | ||
![]() |
d7298eeb80 | ||
![]() |
c18d04e104 | ||
![]() |
8b5b06d116 | ||
![]() |
7fb447897e | ||
![]() |
9c5470744f | ||
![]() |
bd4ca7b848 | ||
![]() |
3a74db145a | ||
![]() |
6bf5e03336 | ||
![]() |
24025524ab | ||
![]() |
80ba7e9934 | ||
![]() |
a5c50b1301 | ||
![]() |
318d38a1da | ||
![]() |
08ae7b0229 | ||
![]() |
ee0f104262 | ||
![]() |
a30c04bab6 | ||
![]() |
056c6f3917 | ||
![]() |
10f15431ff | ||
![]() |
1709f708ed | ||
![]() |
4475a8d914 | ||
![]() |
00d1cddf37 | ||
![]() |
a39c1d3248 | ||
![]() |
dec24ece73 | ||
![]() |
fd33e54c20 | ||
![]() |
af3357bfdc | ||
![]() |
761cf6a47e | ||
![]() |
7e2d55ece4 | ||
![]() |
0e66db223c | ||
![]() |
22e865c66a | ||
![]() |
3679c11c34 | ||
![]() |
55575623c5 | ||
![]() |
40df1d71cf | ||
![]() |
c2d981e4d1 | ||
![]() |
aadde256eb | ||
![]() |
60cb5684c2 | ||
![]() |
8cef088bba | ||
![]() |
7a2cb27c1f | ||
![]() |
033cfc4922 | ||
![]() |
bcbbbcd7b3 | ||
![]() |
baa5f2d9a0 | ||
![]() |
7d1c453960 | ||
![]() |
4dc703c855 | ||
![]() |
58ffaf1bfa | ||
![]() |
d1c6efa2b6 | ||
![]() |
595e528258 | ||
![]() |
95cb881f56 | ||
![]() |
702b83870f | ||
![]() |
e201e27842 | ||
![]() |
a965c32188 | ||
![]() |
982f864cc0 | ||
![]() |
b054a1e09a | ||
![]() |
b3bdd5d8ce | ||
![]() |
47f9a509b1 | ||
![]() |
a49181f75d | ||
![]() |
1d8fa4e3ea | ||
![]() |
758d86f903 | ||
![]() |
a82d657b6b | ||
![]() |
985e2febf4 | ||
![]() |
40be3cc290 | ||
![]() |
087594161e | ||
![]() |
a9d0f3e9a4 | ||
![]() |
44c85a8a46 | ||
![]() |
55b8042c98 | ||
![]() |
2596fe0252 | ||
![]() |
1e89fa5d32 | ||
![]() |
7d05ecab9a | ||
![]() |
f7218f67e2 | ||
![]() |
cdcfc69e05 | ||
![]() |
d57ee7b7ab | ||
![]() |
fd056913d8 | ||
![]() |
c8ce9ec772 | ||
![]() |
6a65f86bf9 | ||
![]() |
42a22f1377 | ||
![]() |
86fe4404ef | ||
![]() |
6fa0ab4734 | ||
![]() |
7759aad68f | ||
![]() |
47a4d1ab0a | ||
![]() |
38c8fec985 | ||
![]() |
e9a76efc3b | ||
![]() |
cf7aaa5059 | ||
![]() |
dc265085a8 | ||
![]() |
03f5bb322d | ||
![]() |
2e2ebab433 | ||
![]() |
a45d9d30b9 | ||
![]() |
7a1929797c | ||
![]() |
1ac9a8a3bf | ||
![]() |
f98f2bcc8e | ||
![]() |
eda33e2032 | ||
![]() |
cf9258949a | ||
![]() |
ae530fec1b | ||
![]() |
3bcc415c06 | ||
![]() |
72fdd05358 | ||
![]() |
798c77464e | ||
![]() |
69600fdbe3 | ||
![]() |
03dba1fe20 | ||
![]() |
2499b13f51 | ||
![]() |
c682a94a07 | ||
![]() |
f28f3d1a07 | ||
![]() |
af832247fc | ||
![]() |
a5aef038ef | ||
![]() |
fce886f077 | ||
![]() |
7214479bc4 | ||
![]() |
876a421ad7 | ||
![]() |
8292f97469 | ||
![]() |
f5ee512a70 | ||
![]() |
0ecc08750b | ||
![]() |
4326523194 | ||
![]() |
465245eb85 | ||
![]() |
7ab90720ff | ||
![]() |
b642be2c91 | ||
![]() |
cfc8bac26f | ||
![]() |
e754af0e08 | ||
![]() |
bf37bf44c7 | ||
![]() |
9a39adebae | ||
![]() |
bdaab4b412 | ||
![]() |
e89efc9d39 | ||
![]() |
05808241b9 | ||
![]() |
38956e0f4a | ||
![]() |
699cff429c | ||
![]() |
f6908837ee | ||
![]() |
9c16bb11b8 | ||
![]() |
e02f543808 | ||
![]() |
0e74afa358 | ||
![]() |
53d43f7933 | ||
![]() |
0597269fc4 | ||
![]() |
1554d52b00 | ||
![]() |
3c09bb9475 | ||
![]() |
43238cf6e4 | ||
![]() |
7958239f7e | ||
![]() |
2eb731e721 | ||
![]() |
ade2c5e269 | ||
![]() |
2ddfa5c9a1 | ||
![]() |
1a794da1fe | ||
![]() |
dd1f3b820f | ||
![]() |
39e8b5b9ad | ||
![]() |
cccb0ca00a | ||
![]() |
ade59eebf0 | ||
![]() |
7b2a9a11c3 | ||
![]() |
2e626b8221 | ||
![]() |
4f04ffe133 | ||
![]() |
b5d2d1c7fb | ||
![]() |
d18be7e76c | ||
![]() |
2787059411 | ||
![]() |
5e4d258860 | ||
![]() |
79b6a75703 | ||
![]() |
723dee6620 | ||
![]() |
cbcee62444 | ||
![]() |
4349087272 | ||
![]() |
83717bda02 | ||
![]() |
333c54f3a2 | ||
![]() |
80e6d02509 | ||
![]() |
4484b885d4 | ||
![]() |
2b788fd258 | ||
![]() |
c4ddc4a119 | ||
![]() |
3d325015af | ||
![]() |
f50bae84b1 | ||
![]() |
a55b3ecc9c | ||
![]() |
6bd86d6032 | ||
![]() |
ca843987f7 | ||
![]() |
fdea09518c | ||
![]() |
b6d031a4ba | ||
![]() |
3d730884ce | ||
![]() |
b20f9d6e50 | ||
![]() |
5973aeca5f | ||
![]() |
dd6e17e97e | ||
![]() |
b423b1980b | ||
![]() |
43ff8b2a8d | ||
![]() |
c80f703ecd | ||
![]() |
bd4b7b3ad3 | ||
![]() |
6f3f1fd392 | ||
![]() |
6b4a32a1b3 | ||
![]() |
033a956e21 | ||
![]() |
a23058ce4b | ||
![]() |
b61f3063d9 | ||
![]() |
d530ab4f23 | ||
![]() |
4677579f9a | ||
![]() |
4a992dc350 | ||
![]() |
fb0c22fb4b | ||
![]() |
607b285443 | ||
![]() |
de14b30570 | ||
![]() |
06529c3854 | ||
![]() |
8faf3fc918 | ||
![]() |
a7d927a83b | ||
![]() |
060924c19a | ||
![]() |
bb67dca507 | ||
![]() |
9526f1d4dc | ||
![]() |
8ce192ceba | ||
![]() |
d0f7393ebe | ||
![]() |
fe3071ba18 | ||
![]() |
a64e2ea445 | ||
![]() |
138cc3c458 | ||
![]() |
aeaa39969b | ||
![]() |
ba8d38a761 | ||
![]() |
05b68db22d | ||
![]() |
3f2f0a7e67 | ||
![]() |
eb4fc032ff | ||
![]() |
6565fb2d6f | ||
![]() |
27ec7a1282 | ||
![]() |
9ab1772b64 | ||
![]() |
a3883c1cd4 | ||
![]() |
591ec1fad7 | ||
![]() |
a7ee4a6cff | ||
![]() |
98f2cbd51b | ||
![]() |
eb9c64772f | ||
![]() |
8fbe03ee1b | ||
![]() |
21ddba4595 | ||
![]() |
cbc415d32b | ||
![]() |
71a623b5e0 | ||
![]() |
eddb096adb | ||
![]() |
f73b703123 | ||
![]() |
9e39b2f81d | ||
![]() |
fed0cfff6a | ||
![]() |
cc5a4a6fd8 | ||
![]() |
7c7f89b2ac | ||
![]() |
2a2a55b9fa | ||
![]() |
451c172a70 | ||
![]() |
5648469247 | ||
![]() |
c6e571aab1 | ||
![]() |
f2a89063c6 | ||
![]() |
e59fdded1b | ||
![]() |
56ba9f1ee5 | ||
![]() |
5e77c6a3bb | ||
![]() |
4c7ca93dcc | ||
![]() |
947e7a0fb1 | ||
![]() |
d96b8027bd | ||
![]() |
8e17a8780b | ||
![]() |
36afc4a215 | ||
![]() |
c4d4b91488 | ||
![]() |
b9dda9337a | ||
![]() |
5cd2c25489 | ||
![]() |
598be273aa | ||
![]() |
2a9741e826 | ||
![]() |
44a3a9dcba | ||
![]() |
da7af617f7 | ||
![]() |
4bd4d17c5c | ||
![]() |
20036b5de0 | ||
![]() |
582fc5d359 | ||
![]() |
c9777b39ed | ||
![]() |
3bf5e59c63 | ||
![]() |
bb8d835034 | ||
![]() |
f8563adbcc | ||
![]() |
e616ced26e | ||
![]() |
264a1d67f6 | ||
![]() |
7d56a454dc | ||
![]() |
a86d64b828 | ||
![]() |
ddf5924917 | ||
![]() |
f50d833a0e | ||
![]() |
91ebcfab33 | ||
![]() |
27b72aa1e9 | ||
![]() |
e7bb9bfb56 | ||
![]() |
bbac7b91f0 | ||
![]() |
ecf8af193b | ||
![]() |
ca1f5cf781 | ||
![]() |
140dc7b23c | ||
![]() |
f0629cb151 | ||
![]() |
d60a4c5767 | ||
![]() |
555936d939 | ||
![]() |
79ceeb1ada | ||
![]() |
e811422c44 | ||
![]() |
4a0f285a2c | ||
![]() |
a746cc1779 | ||
![]() |
ac8ee9e4dd | ||
![]() |
9e521b244d | ||
![]() |
eb228b0e45 | ||
![]() |
b64ba76bc5 | ||
![]() |
bdf97fff58 | ||
![]() |
fa3d7d831d | ||
![]() |
da4e9d57c1 | ||
![]() |
d7ea086c5d | ||
![]() |
9e56672019 | ||
![]() |
7dad78eb91 | ||
![]() |
d15c6e59fa | ||
![]() |
1c086455e2 | ||
![]() |
9b78cc3406 | ||
![]() |
c83d5f2f17 | ||
![]() |
53c853dae5 | ||
![]() |
b6423e5090 | ||
![]() |
5877be38df | ||
![]() |
7da6a97d15 | ||
![]() |
2b66db8216 | ||
![]() |
46e4810391 | ||
![]() |
f7b80bf34d | ||
![]() |
9c33235a83 | ||
![]() |
04ac2a383e | ||
![]() |
dff52f8ca0 | ||
![]() |
23a1182d00 | ||
![]() |
b3a38224af | ||
![]() |
1b519fbc33 | ||
![]() |
49e84c4a7f | ||
![]() |
557a25a6b5 | ||
![]() |
a440eb6bc7 | ||
![]() |
5f32d75700 | ||
![]() |
dddfee3920 | ||
![]() |
e21bdc3b22 | ||
![]() |
3f5e040a5a | ||
![]() |
4096583b1c | ||
![]() |
33afc04d86 | ||
![]() |
d082929dee | ||
![]() |
6ee74461ed | ||
![]() |
a446218933 | ||
![]() |
35e0e112bd | ||
![]() |
f28aaac518 | ||
![]() |
fbcd210578 | ||
![]() |
fcd17f8859 | ||
![]() |
af7c71e762 | ||
![]() |
e1b9946448 | ||
![]() |
7f4f63775d | ||
![]() |
208ff18a5d | ||
![]() |
c22b118dd6 | ||
![]() |
96dbb5ccbc | ||
![]() |
2c47644ea8 | ||
![]() |
161b18e5e8 | ||
![]() |
55394d4137 | ||
![]() |
eca0bc5205 | ||
![]() |
a89d386541 | ||
![]() |
eb39662e36 | ||
![]() |
b2a36c24dc | ||
![]() |
0b390f356f | ||
![]() |
61ceed0726 | ||
![]() |
60e41b425b | ||
![]() |
41d9dd7c21 | ||
![]() |
c3741cb912 | ||
![]() |
ac8db75a3f | ||
![]() |
8d9a16cef6 | ||
![]() |
65fcb25952 | ||
![]() |
ab31f20508 | ||
![]() |
38155190c5 | ||
![]() |
66b7d83d7e | ||
![]() |
d4becb575f | ||
![]() |
bc4f1f3080 | ||
![]() |
328938d268 | ||
![]() |
f8bf1d45fc | ||
![]() |
5521d06bc0 | ||
![]() |
e55536e581 | ||
![]() |
457a47b36f | ||
![]() |
ad94d03576 | ||
![]() |
d993eb2a85 | ||
![]() |
f09aa7749b | ||
![]() |
914476ffe7 | ||
![]() |
41abde5db8 | ||
![]() |
916276e36a | ||
![]() |
8189503a69 | ||
![]() |
e5916b98b9 | ||
![]() |
1d77c2306f | ||
![]() |
e6ec733303 | ||
![]() |
6f3ad2dea3 | ||
![]() |
377c7ed1d5 | ||
![]() |
128df65f54 | ||
![]() |
8068e471d1 | ||
![]() |
494f75917c | ||
![]() |
52cc9b1cd3 | ||
![]() |
06de8e2b66 | ||
![]() |
b03f06a1a2 | ||
![]() |
1831261cfd | ||
![]() |
43c794d242 | ||
![]() |
7d39c51e31 | ||
![]() |
d0a23491df | ||
![]() |
36c5b7012f | ||
![]() |
26b552bb58 | ||
![]() |
285c0f4543 | ||
![]() |
6d6671c356 | ||
![]() |
6088ebd617 | ||
![]() |
6c05e02077 | ||
![]() |
0895a085a1 | ||
![]() |
88508679b0 | ||
![]() |
63fb46578a | ||
![]() |
07e22b0c14 | ||
![]() |
63d72ee867 | ||
![]() |
8bc7121394 | ||
![]() |
f2ffb0fdce | ||
![]() |
7bcbaea492 | ||
![]() |
d0f6d903e2 | ||
![]() |
7925ab205d | ||
![]() |
35bfe0694b | ||
![]() |
bd634c828b | ||
![]() |
720d83ef3a | ||
![]() |
c14be8f57e | ||
![]() |
76757811cb | ||
![]() |
f80acab4c2 | ||
![]() |
5b8be2f5d4 | ||
![]() |
6fcce84623 | ||
![]() |
068ee52301 | ||
![]() |
627f4f8d21 | ||
![]() |
0304ed37c3 | ||
![]() |
190be2a1b5 | ||
![]() |
caf3ae1ab5 | ||
![]() |
ecef34a8da | ||
![]() |
204ce2b100 | ||
![]() |
eaea3a416d | ||
![]() |
cf3b933e59 | ||
![]() |
7f1041c434 | ||
![]() |
42897bde35 | ||
![]() |
0f76186663 | ||
![]() |
d304509c0d | ||
![]() |
2a6b9fb237 | ||
![]() |
9d648f74dd | ||
![]() |
f3e066af45 | ||
![]() |
907850cb80 | ||
![]() |
c6b6bfde70 | ||
![]() |
ae735f6a1e | ||
![]() |
fd0baeb5a4 | ||
![]() |
bfdb839d01 | ||
![]() |
35e9294d87 | ||
![]() |
b791896fc6 | ||
![]() |
043f6c2569 | ||
![]() |
332e57d59f | ||
![]() |
a3456637cd | ||
![]() |
5650ea29b5 | ||
![]() |
c9e305808b | ||
![]() |
efe36603f8 | ||
![]() |
96fdd1a41a | ||
![]() |
0b9233f44b | ||
![]() |
5a9e3a8645 | ||
![]() |
3900573a7c | ||
![]() |
d9c260b865 | ||
![]() |
a97d66d6e4 | ||
![]() |
5256a7f276 | ||
![]() |
eed7bfff73 | ||
![]() |
d6c215c9c6 | ||
![]() |
b6ca5a1717 | ||
![]() |
1350eff0f5 | ||
![]() |
bf66a9e19a | ||
![]() |
5a1ca738f6 | ||
![]() |
63d6902605 | ||
![]() |
de89979e45 | ||
![]() |
fe424d8966 | ||
![]() |
b0e42bebf1 | ||
![]() |
cf3b7f8d18 | ||
![]() |
83c30987eb | ||
![]() |
1cf69e231f | ||
![]() |
6d776c8a97 | ||
![]() |
974369966a | ||
![]() |
cdc1866720 | ||
![]() |
4915840035 | ||
![]() |
0ff942342f | ||
![]() |
990a0a40ba | ||
![]() |
405c9e7650 | ||
![]() |
dc2370ebf3 | ||
![]() |
439d683fdb | ||
![]() |
15e6ea0a4d | ||
![]() |
c9a8d8f89d | ||
![]() |
e9a6973d16 | ||
![]() |
8a537755a0 | ||
![]() |
ff47ff7366 | ||
![]() |
53feb26fa9 | ||
![]() |
f8e32d260e | ||
![]() |
bb60ea028e | ||
![]() |
fb040de538 | ||
![]() |
e76bf0c4da | ||
![]() |
db77ddce0f | ||
![]() |
1ed65ba8f6 | ||
![]() |
0fc7aa3767 | ||
![]() |
f8d2cfd1f2 | ||
![]() |
252784c029 | ||
![]() |
e6fecc5020 | ||
![]() |
c973d4edd6 | ||
![]() |
2dc1baf2e8 | ||
![]() |
b0e3ff1231 | ||
![]() |
17154e33d2 | ||
![]() |
37d609c2bd | ||
![]() |
e78414ac1e | ||
![]() |
f3dddef6a4 | ||
![]() |
3d66556acf | ||
![]() |
433d726d75 | ||
![]() |
6596474389 | ||
![]() |
7b5f295a9b | ||
![]() |
5ff21ad589 | ||
![]() |
8cd1de6b64 | ||
![]() |
f4fa80a8cf | ||
![]() |
00e12b8bd8 | ||
![]() |
083c59550a | ||
![]() |
b5c1c6b974 | ||
![]() |
0dd2639d97 | ||
![]() |
e2d74220d5 | ||
![]() |
f0959c2796 | ||
![]() |
6b26974ce7 | ||
![]() |
a6b4378533 | ||
![]() |
512f044ec6 | ||
![]() |
67c99fb322 | ||
![]() |
57d0869e65 | ||
![]() |
64f051ece3 | ||
![]() |
eba878dea1 | ||
![]() |
a2825be165 | ||
![]() |
8f8d901787 | ||
![]() |
80f93b471a | ||
![]() |
36a359eb6f | ||
![]() |
0dc3e1c8a4 | ||
![]() |
17dbe15dc2 | ||
![]() |
72435cd0e8 | ||
![]() |
a12323cf2e | ||
![]() |
ecbcb8f63c | ||
![]() |
ebc013a204 | ||
![]() |
f861bbece8 | ||
![]() |
86113d1429 | ||
![]() |
9f8c8b4c10 | ||
![]() |
1ec6562799 | ||
![]() |
b729f53d9d | ||
![]() |
cd630536e2 | ||
![]() |
cdbb4eefcc | ||
![]() |
b015abf85f | ||
![]() |
a9e6874fe0 | ||
![]() |
47a5412eeb | ||
![]() |
70402ba46f | ||
![]() |
d3c8af196d | ||
![]() |
955fd1d247 | ||
![]() |
995da0f611 | ||
![]() |
9c79f54994 | ||
![]() |
5a3aa9db18 | ||
![]() |
e637034a8c | ||
![]() |
62987fbbe1 | ||
![]() |
5dbbf340a0 | ||
![]() |
31ae58435e | ||
![]() |
1ff381d0b7 | ||
![]() |
16777de1a9 | ||
![]() |
24adfcb9f2 | ||
![]() |
9e036d259f | ||
![]() |
df5695a220 | ||
![]() |
aa687ade0b | ||
![]() |
422256122d | ||
![]() |
2ebac920f2 | ||
![]() |
b678bf384c | ||
![]() |
9a4773610a | ||
![]() |
d895affffa | ||
![]() |
1a207e3543 | ||
![]() |
7bc4417eff | ||
![]() |
7afffe1809 | ||
![]() |
4080901576 | ||
![]() |
deeb8b987a | ||
![]() |
f142a9d52c | ||
![]() |
7bc9347909 | ||
![]() |
c6176d0b1e | ||
![]() |
cef91e442a | ||
![]() |
45e0504dab | ||
![]() |
ad5baf2823 | ||
![]() |
a89f186f40 | ||
![]() |
0951720512 | ||
![]() |
0d251a9d43 | ||
![]() |
e025f22553 | ||
![]() |
a76bbba2a6 | ||
![]() |
a24b385560 | ||
![]() |
2934319591 | ||
![]() |
ca708c3f56 | ||
![]() |
15668ee7b5 | ||
![]() |
47e740fd88 | ||
![]() |
ae0b63eb50 | ||
![]() |
9de641eb66 | ||
![]() |
9aff925c94 | ||
![]() |
02bc6b6bce | ||
![]() |
5fe3c34167 | ||
![]() |
4ea2ab0ddb | ||
![]() |
ed06bbda9d | ||
![]() |
7c70c247b9 | ||
![]() |
0761be3258 | ||
![]() |
4329b43b76 | ||
![]() |
8836f90251 | ||
![]() |
a36e8b19f8 | ||
![]() |
0d487b6490 | ||
![]() |
4ab9b14bcb | ||
![]() |
fc0aac9877 | ||
![]() |
3ec92af160 | ||
![]() |
7fe8ad9b35 | ||
![]() |
58d55f820f | ||
![]() |
9927eb62eb | ||
![]() |
8b89c60418 | ||
![]() |
62eff7c4c3 | ||
![]() |
858130da9c | ||
![]() |
a62d3d0e57 | ||
![]() |
2df077df26 | ||
![]() |
4176303d6f | ||
![]() |
dce754182e | ||
![]() |
a2186f3fa4 | ||
![]() |
dc15a4aabe | ||
![]() |
b0eb7aacdd | ||
![]() |
6f08d7f5b9 | ||
![]() |
4996c2db0d | ||
![]() |
9e95c7e71c | ||
![]() |
1f36d35d23 | ||
![]() |
3acd41027b | ||
![]() |
ff5135c2a3 | ||
![]() |
7de72bd99a | ||
![]() |
b771e86f8d | ||
![]() |
b25209f114 | ||
![]() |
0a58484d6d | ||
![]() |
c702699f45 | ||
![]() |
99653613ee | ||
![]() |
4acba7de18 | ||
![]() |
8765cf4d3f | ||
![]() |
c78b023675 | ||
![]() |
c9f0c5f475 | ||
![]() |
33867d4d1f | ||
![]() |
6e07d42a1b | ||
![]() |
67811d87fa | ||
![]() |
d9924010d4 | ||
![]() |
0ddc179737 | ||
![]() |
a125219751 | ||
![]() |
93b53214f6 | ||
![]() |
50b0e8babf | ||
![]() |
06d6a370b7 | ||
![]() |
4890447787 | ||
![]() |
0bf2c5c580 | ||
![]() |
00359b1a4e | ||
![]() |
c6225f7117 | ||
![]() |
173fa526e9 | ||
![]() |
555d5cdbbe | ||
![]() |
4ed7c6c242 | ||
![]() |
9a01ace34d | ||
![]() |
6e20ad6edb | ||
![]() |
68d1bbb359 | ||
![]() |
c081155c4f | ||
![]() |
0b02c5d17c | ||
![]() |
cd577f5108 | ||
![]() |
d3882edebc | ||
![]() |
cf8fbf5870 | ||
![]() |
3b6efc1786 | ||
![]() |
cd427c66be | ||
![]() |
9467dd89bf | ||
![]() |
57590c48bb | ||
![]() |
f4b3ed33a2 | ||
![]() |
8af26827de |
9
.codespellrc
Normal file
9
.codespellrc
Normal file
@@ -0,0 +1,9 @@
|
||||
[codespell]
|
||||
# Ref: https://github.com/codespell-project/codespell#using-a-config-file
|
||||
skip = .git*,*.svg,go.sum,package-lock.json,*.css,.codespellrc,locales,stopwords.*,shortwords.*,countries.*,keywords.json,smallwords.*
|
||||
check-hidden = true
|
||||
# ACRONYMS and generally mixed case/Capitalized words
|
||||
# Also ignore some German
|
||||
ignore-regex = ^(SMethod=shal|biuld: build)$|https://\S+|\b([A-Z][a-zA-Z]+|ist auf)\b|"(datin|alis|hel)"|\bfixe == false\b
|
||||
# common variables or other tricky cases
|
||||
ignore-words-list = renderd,nd,folde,crate,ue,fo,ist,alo,mot,te,admiraal
|
@@ -1,4 +1,4 @@
|
||||
# Local build files and directories
|
||||
# Local build files and directories:
|
||||
/photos/*
|
||||
/frontend/node_modules/*
|
||||
/node_modules
|
||||
@@ -7,32 +7,61 @@
|
||||
/assets/facenet
|
||||
/assets/nasnet
|
||||
/assets/nsfw
|
||||
/assets/efficientnet
|
||||
/assets/imagenet
|
||||
/assets/resnet
|
||||
/assets/vision
|
||||
/assets/models
|
||||
/storage
|
||||
/build
|
||||
/photoprism
|
||||
/photoprism-*
|
||||
/coverage.*
|
||||
/frontend/tests/acceptance/screenshots
|
||||
/test/
|
||||
/specs/
|
||||
|
||||
# Custom config, database, log, and temporary files
|
||||
/tmp/
|
||||
.env
|
||||
# Docker configuration files:
|
||||
.dockerignore
|
||||
*.log
|
||||
*.jsonl
|
||||
*.db
|
||||
*.db-journal
|
||||
Dockerfile
|
||||
docker-compose*
|
||||
compose.yaml
|
||||
compose.*.yaml
|
||||
*.override.yml
|
||||
*.override.yaml
|
||||
*.tmp.yml
|
||||
*.tmp.yaml
|
||||
|
||||
# Automatically generated files, e.g. by editors and operating systems
|
||||
# Customization, database, log, and temporary files:
|
||||
*.socket
|
||||
*.lock
|
||||
*.sock
|
||||
*.pid
|
||||
*.log
|
||||
*.jsonl
|
||||
*.db
|
||||
*.db-journal
|
||||
*.sqlite
|
||||
*.override.yml
|
||||
*.tmp.yml
|
||||
*.override.yaml
|
||||
*.tmp.yaml
|
||||
*.out
|
||||
*.test
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
*.tmp
|
||||
*.img
|
||||
*.img.xz
|
||||
*.img.gz
|
||||
/*.zip
|
||||
/coverage.*
|
||||
__pycache__
|
||||
venv
|
||||
.venv
|
||||
.env
|
||||
.tmp
|
||||
.nv
|
||||
.eslintcache
|
||||
.gocache
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
@@ -42,10 +71,12 @@ ehthumbs.db
|
||||
Thumbs.db
|
||||
.heartbeat
|
||||
.idea
|
||||
.glide
|
||||
.codex
|
||||
.local
|
||||
*~
|
||||
.goutputstream*
|
||||
.c9revisions
|
||||
.settings
|
||||
.swp
|
||||
.tmp
|
||||
.glide
|
||||
/tmp/
|
||||
|
10
.github/ISSUE_TEMPLATE/question.md
vendored
10
.github/ISSUE_TEMPLATE/question.md
vendored
@@ -1,18 +1,18 @@
|
||||
---
|
||||
name: Question
|
||||
about: You have a general question or need assistance
|
||||
title: 'STOP! DO NOT PROCEED, USE GITHUB DISCUSSIONS INSTEAD - THANK YOU'
|
||||
labels: technical-support
|
||||
title: 'PLEASE DO NOT OPEN AN ISSUE FOR YOUR QUESTION, AND USE GITHUB DISCUSSIONS OR OUR COMMUNITY CHAT INSTEAD'
|
||||
labels: question
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
FOR GENERAL QUESTIONS, TECHNICAL SUPPORT, AND TO GET TO KNOW OTHER COMMUNITY MEMBERS:
|
||||
|
||||
<https://github.com/photoprism/photoprism/discussions>
|
||||
<https://github.com/photoprism/photoprism/discussions>
|
||||
|
||||
OUR TROUBLESHOOTING CHECKLISTS HELP YOU QUICKLY DIAGNOSE AND FIX COMMON PROBLEMS:
|
||||
|
||||
<https://docs.photoprism.app/getting-started/troubleshooting/>
|
||||
<https://docs.photoprism.app/getting-started/troubleshooting/>
|
||||
|
||||
DO NOT PROCEED, THANK YOU!
|
||||
PLEASE DO NOT OPEN AN ISSUE FOR YOUR QUESTION, AND USE GITHUB DISCUSSIONS OR OUR COMMUNITY CHAT INSTEAD. THANK YOU VERY MUCH!
|
||||
|
57
.github/PULL_REQUEST_TEMPLATE.md
vendored
57
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,33 +1,34 @@
|
||||
<!--
|
||||
|
||||
Thank you for your interest in contributing!
|
||||
|
||||
Because we want to create the best possible product for our users, we have a set of criteria to ensure that all submissions are acceptable, see https://docs.photoprism.app/developer-guide/pull-requests/ for details.
|
||||
|
||||
(1) Please provide a concise description of your pull request.
|
||||
|
||||
- What does it implement / fix / improve? Why?
|
||||
- Are the changes related to an existing issue?
|
||||
|
||||
(2) After you submit your first pull request, you will be asked to accept our CLA, see https://www.photoprism.app/cla.
|
||||
|
||||
(3) Finally, please confirm that the following criteria are met by replacing "[ ]" with "[x]" (also possible at a later time).
|
||||
|
||||
-->
|
||||
|
||||
Acceptance Criteria:
|
||||
|
||||
- [ ] Features and enhancements must be fully implemented so that they can be released at any time without additional work
|
||||
- [ ] Automated unit and/or acceptance tests are mandatory to ensure the changes work as expected and to reduce repetitive manual work
|
||||
- [ ] Frontend components must be responsive to work and look properly on phones, tablets, and desktop computers; you must have tested them on all major browsers and different devices
|
||||
- [ ] Documentation and translation updates should be provided if needed
|
||||
- [ ] In case you submit database-related changes, they must be tested and compatible with SQLite 3 and MariaDB 10.5.12+
|
||||
### Description
|
||||
|
||||
<!--
|
||||
We appreciate your interest in contributing! Please provide a brief description of your changes so that we know what is included in this pull request, and confirm that it meets the acceptance criteria:
|
||||
|
||||
Since reviewing, testing and finally merging pull requests requires significant resources on our side, this can take several months if it's not just a small fix, especially if extensive testing is required to prevent bugs from getting into our stable version.
|
||||
|
||||
We thank you for your patience! :)
|
||||
|
||||
What does it aim to implement, fix or improve? Why?
|
||||
-->
|
||||
|
||||
These changes implement/fix/improve...
|
||||
|
||||
#### Related Issues
|
||||
|
||||
- Links to issues that this PR fixes, implements, or is otherwise related to...
|
||||
|
||||
### Acceptance Criteria
|
||||
|
||||
<!-- You may add additional criteria and/or remove criteria that do not apply, e.g. because your PR does not include frontend changes: -->
|
||||
|
||||
- [ ] New features or enhancements are fully implemented and do not break existing functionality, so that they can be released at any time without requiring additional work
|
||||
- [ ] Automated unit and/or acceptance tests are included to ensure that changes work as expected and to reduce repetitive manual work
|
||||
- [ ] Documentation has been / will be updated, especially as it relates to new configuration options or potentially disruptive changes
|
||||
- [ ] The user interface has been tested on Chrome, Safari, and Firefox and is fully responsive for use on phones, tablets, and desktop computers
|
||||
- [ ] Database-related changes have been successfully tested with SQLite 3 and MariaDB 10.5.12+
|
||||
|
||||
<!--
|
||||
Contribution Agreement:
|
||||
|
||||
After submitting your first pull request, you will be asked to confirm our contribution agreement. This allows us to safely use your Contribution in all our projects without risking unexpected legal disputes or having to repeatedly ask for permission.
|
||||
The agreement is solely for our protection and that of our users. It does not grant us exclusive rights to your code.
|
||||
|
||||
PhotoPrism UG ("PhotoPrism", "we" or "us") hereby confirms to you that, to the fullest extent permitted by applicable law, this Contribution is provided "AS IS" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OR CONDITIONS OF NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. You have no obligation to provide support, maintenance, or other services for your Contribution.
|
||||
|
||||
Thank you very much! 🌈💎✨
|
||||
-->
|
86
.github/copilot-instructions.md
vendored
Normal file
86
.github/copilot-instructions.md
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
# Instructions for GitHub Copilot
|
||||
|
||||
## Purpose
|
||||
|
||||
- Provide Copilot with the single sources of truth for building, testing, and contributing to PhotoPrism.
|
||||
- Improve PR reviews and code suggestions by aligning them with our documented workflows and style.
|
||||
|
||||
## Single Sources of Truth (SOT)
|
||||
|
||||
- Makefile targets (always prefer existing targets): https://github.com/photoprism/photoprism/blob/develop/Makefile
|
||||
- Developer Guide – Setup: https://docs.photoprism.app/developer-guide/setup/
|
||||
- Developer Guide – Tests: https://docs.photoprism.app/developer-guide/tests/
|
||||
- Contributing: https://github.com/photoprism/photoprism/blob/develop/CONTRIBUTING.md
|
||||
- Security: https://github.com/photoprism/photoprism/blob/develop/SECURITY.md
|
||||
- REST API (Swagger): https://docs.photoprism.dev/
|
||||
- REST API Guide: https://docs.photoprism.app/developer-guide/api/
|
||||
- Agents reference for tools/commands: https://github.com/photoprism/photoprism/blob/develop/AGENTS.md
|
||||
|
||||
## Build & Run (local dev; use Makefile first)
|
||||
|
||||
- Show tasks: `make help`
|
||||
- Build local image: `make docker-build`
|
||||
- Start dev env: `docker compose up` (add `-d` for detached)
|
||||
- Logs: `docker compose logs -f --tail=100 photoprism`
|
||||
- Open app: http://localhost:2342/ (HTTP) / https://app.localssl.dev/ (TLS via Traefik when enabled)
|
||||
- From the dev container:
|
||||
- Install deps: `make dep`
|
||||
- Build frontend: `make build-js` (or `cd frontend && npm run build`)
|
||||
- Build backend: `make build-go`
|
||||
- Watch frontend: `make watch-js` (stop with Ctrl+C)
|
||||
- Run server binary: `./photoprism start`
|
||||
|
||||
## Tests & Lint
|
||||
|
||||
- Full tests: `make test`
|
||||
- Frontend tests (Vitest): `make test-js` (watch: `make vitest-watch`, coverage: `make vitest-coverage`)
|
||||
- Backend tests: `make test-go`
|
||||
- Formatting:
|
||||
- Go: `go fmt`, `goimports` (see `make fmt`, `make fmt-go`)
|
||||
- JS/Vue: use scripts in `frontend/package.json` (ESLint + Prettier)
|
||||
|
||||
## Project Structure & Languages
|
||||
|
||||
- Backend: Go (`internal/`, `pkg/`, `cmd/`) + MariaDB/SQLite
|
||||
- Frontend: Vue 3 + Vuetify 3 (`frontend/`)
|
||||
- Docker/compose for dev/CI; Traefik used for local TLS in dev profile when enabled.
|
||||
|
||||
## Code Review Instructions (for Copilot)
|
||||
|
||||
- Respect SOT above; do not invent flags, env vars, or Compose options. If a command/env var is not in the docs/Makefile/CLI help, say “not documented” and suggest checking the SOT.
|
||||
- Prefer minimal, surgical diffs. Propose changes as concrete patches and reference the relevant Makefile target or doc section.
|
||||
- Before suggesting refactors, check tests and build tasks exist and can pass with the change. If tests are missing, suggest specific Vitest/Go test snippets.
|
||||
- Security: never suggest committing secrets; prefer env vars and `.env` in dev only. Point to SECURITY.md for disclosures.
|
||||
- Data safety: never run or recommend destructive CLI operations in examples without explicit backups and `--yes`. Avoid `photoprism reset`, `photoprism users reset`, `photoprism auth reset`, or `photoprism audit reset` in PR comments unless the change is specifically about those commands; if unavoidable, add bold warnings and backup steps.
|
||||
- Database/schema: if a change touches persistence, check for migrations and mention `photoprism migrate` / `migrations` commands.
|
||||
- API changes: align with the REST API docs/spec; include curl examples only if they match current endpoints and auth notes.
|
||||
- UX/i18n: keep UI strings concise, translatable, and consistent; avoid hard-coded language constructs; prefer existing patterns/components.
|
||||
|
||||
## Style & Patterns
|
||||
|
||||
- Go: idiomatic Go, clear error handling, small functions, packages with focused responsibilities. Keep public surface minimal. Add/adjust unit tests.
|
||||
- Vue/JS: options API, store patterns as in existing code, avoid breaking translations. Keep ESLint/Prettier clean.
|
||||
- Config & flags: suggest `photoprism --help`, `photoprism show config-options` or `photoprism show config-yaml` to verify names before using them.
|
||||
|
||||
## Performance & Reliability
|
||||
|
||||
- Prefer using existing caches, workers, and batching strategies referenced in code and Makefile. Consider memory/CPU impact; suggest benchmarks or profiling only when justified.
|
||||
|
||||
## When Unsure
|
||||
|
||||
- Ask for the exact Makefile target or doc link you need, then proceed. Defer to SOT if any conflict arises.
|
||||
|
||||
## References To Help Copilot Answer Questions
|
||||
|
||||
- Show supported formats/filters: run `photoprism show file-formats` and `photoprism show search-filters` (use results rather than guessing).
|
||||
- For CI/dev containers, assume Linux/Unix shell by default; link Windows specifics in Developer Guide FAQ.
|
||||
|
||||
## Output Expectations
|
||||
|
||||
- Prefer short, actionable comments with code blocks that pass tests locally: `make test-js` (frontend) / `make test-go` (backend)
|
||||
- If a suggestion requires additional context (e.g., DB access, external service), call it out explicitly.
|
||||
|
||||
## Safety Checklist Before Proposing a CLI Command
|
||||
|
||||
- Include a dry-run or non-destructive variant if possible.
|
||||
- Recommend creating/using backups before any reset/migrate.
|
13
.github/instructions/backend.instructions.md
vendored
Normal file
13
.github/instructions/backend.instructions.md
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
applyTo:
|
||||
- "internal/**"
|
||||
- "pkg/**"
|
||||
- "cmd/**"
|
||||
---
|
||||
|
||||
For backend changes:
|
||||
|
||||
- Maintain Go style; keep functions small, errors wrapped with context.
|
||||
- Add/update unit tests; ensure `make test-go` passes.
|
||||
- Touching schema? Mention migrations and verify with `photoprism migrations ls`/`migrate`.
|
||||
- For CLI/config, confirm flags/envs via `photoprism --help` / `photoprism show config-options` before suggesting.
|
12
.github/instructions/frontend.instructions.md
vendored
Normal file
12
.github/instructions/frontend.instructions.md
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
applyTo:
|
||||
- "frontend/**"
|
||||
---
|
||||
|
||||
For frontend changes:
|
||||
|
||||
- Keep Vue 3 idioms; prefer options API and existing components.
|
||||
- Run `make build-js` and `make test-js`; fix ESLint/Prettier before proposing changes.
|
||||
- Avoid introducing global state; follow existing store patterns.
|
||||
- Keep strings translatable; don’t hardcode locales.
|
||||
- For performance, avoid unnecessary reactivity and re-renders; justify new deps.
|
22
.gitignore
vendored
22
.gitignore
vendored
@@ -18,6 +18,10 @@
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
*.tmp
|
||||
*.img
|
||||
*.img.xz
|
||||
*.img.gz
|
||||
/*.zip
|
||||
/coverage.*
|
||||
__pycache__
|
||||
@@ -25,7 +29,11 @@ venv
|
||||
.venv
|
||||
.env
|
||||
.tmp
|
||||
.nv
|
||||
.eslintcache
|
||||
.gocache
|
||||
/pro
|
||||
/plus
|
||||
/tmp/
|
||||
/test/
|
||||
*-lock.json
|
||||
@@ -37,6 +45,7 @@ venv
|
||||
/frontend/src/locales/*.mo
|
||||
/frontend/tests_output
|
||||
frontend/coverage/
|
||||
**/__screenshots__/
|
||||
/photoprism
|
||||
/photoprism-*
|
||||
/photos/originals/*
|
||||
@@ -48,8 +57,10 @@ frontend/coverage/
|
||||
/assets/nasnet
|
||||
/assets/nsfw
|
||||
/assets/static/build/
|
||||
/pro
|
||||
/plus
|
||||
/assets/static/maps/
|
||||
/assets/*net
|
||||
/assets/vision
|
||||
/specs/
|
||||
|
||||
# Files created automatically by editors and/or operating systems:
|
||||
.DS_Store
|
||||
@@ -60,8 +71,13 @@ frontend/coverage/
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
.heartbeat
|
||||
.idea
|
||||
.glide
|
||||
.idea
|
||||
.codex
|
||||
.local
|
||||
.project
|
||||
.vscode
|
||||
*.tmproj
|
||||
*~
|
||||
.goutputstream*
|
||||
.c9revisions
|
||||
|
335
.qdrant.yaml
Normal file
335
.qdrant.yaml
Normal file
@@ -0,0 +1,335 @@
|
||||
log_level: INFO
|
||||
|
||||
# Logging configuration
|
||||
# Qdrant logs to stdout. You may configure to also write logs to a file on disk.
|
||||
# Be aware that this file may grow indefinitely.
|
||||
# logger:
|
||||
# # Logging format, supports `text` and `json`
|
||||
# format: text
|
||||
# on_disk:
|
||||
# enabled: true
|
||||
# log_file: path/to/log/file.log
|
||||
# log_level: INFO
|
||||
# # Logging format, supports `text` and `json`
|
||||
# format: text
|
||||
|
||||
storage:
|
||||
# Where to store all the data
|
||||
storage_path: ./storage
|
||||
|
||||
# Where to store snapshots
|
||||
snapshots_path: ./snapshots
|
||||
|
||||
snapshots_config:
|
||||
# "local" or "s3" - where to store snapshots
|
||||
snapshots_storage: local
|
||||
# s3_config:
|
||||
# bucket: ""
|
||||
# region: ""
|
||||
# access_key: ""
|
||||
# secret_key: ""
|
||||
|
||||
# Where to store temporary files
|
||||
# If null, temporary snapshots are stored in: storage/snapshots_temp/
|
||||
temp_path: null
|
||||
|
||||
# If true - point payloads will not be stored in memory.
|
||||
# It will be read from the disk every time it is requested.
|
||||
# This setting saves RAM by (slightly) increasing the response time.
|
||||
# Note: those payload values that are involved in filtering and are indexed - remain in RAM.
|
||||
#
|
||||
# Default: true
|
||||
on_disk_payload: true
|
||||
|
||||
# Maximum number of concurrent updates to shard replicas
|
||||
# If `null` - maximum concurrency is used.
|
||||
update_concurrency: null
|
||||
|
||||
# Write-ahead-log related configuration
|
||||
wal:
|
||||
# Size of a single WAL segment
|
||||
wal_capacity_mb: 32
|
||||
|
||||
# Number of WAL segments to create ahead of actual data requirement
|
||||
wal_segments_ahead: 0
|
||||
|
||||
# Normal node - receives all updates and answers all queries
|
||||
node_type: "Normal"
|
||||
|
||||
# Listener node - receives all updates, but does not answer search/read queries
|
||||
# Useful for setting up a dedicated backup node
|
||||
# node_type: "Listener"
|
||||
|
||||
performance:
|
||||
# Number of parallel threads used for search operations. If 0 - auto selection.
|
||||
max_search_threads: 0
|
||||
|
||||
# Max number of threads (jobs) for running optimizations across all collections, each thread runs one job.
|
||||
# If 0 - have no limit and choose dynamically to saturate CPU.
|
||||
# Note: each optimization job will also use `max_indexing_threads` threads by itself for index building.
|
||||
max_optimization_threads: 0
|
||||
|
||||
# CPU budget, how many CPUs (threads) to allocate for an optimization job.
|
||||
# If 0 - auto selection, keep 1 or more CPUs unallocated depending on CPU size
|
||||
# If negative - subtract this number of CPUs from the available CPUs.
|
||||
# If positive - use this exact number of CPUs.
|
||||
optimizer_cpu_budget: 0
|
||||
|
||||
# Prevent DDoS of too many concurrent updates in distributed mode.
|
||||
# One external update usually triggers multiple internal updates, which breaks internal
|
||||
# timings. For example, the health check timing and consensus timing.
|
||||
# If null - auto selection.
|
||||
update_rate_limit: null
|
||||
|
||||
# Limit for number of incoming automatic shard transfers per collection on this node, does not affect user-requested transfers.
|
||||
# The same value should be used on all nodes in a cluster.
|
||||
# Default is to allow 1 transfer.
|
||||
# If null - allow unlimited transfers.
|
||||
#incoming_shard_transfers_limit: 1
|
||||
|
||||
# Limit for number of outgoing automatic shard transfers per collection on this node, does not affect user-requested transfers.
|
||||
# The same value should be used on all nodes in a cluster.
|
||||
# Default is to allow 1 transfer.
|
||||
# If null - allow unlimited transfers.
|
||||
#outgoing_shard_transfers_limit: 1
|
||||
|
||||
# Enable async scorer which uses io_uring when rescoring.
|
||||
# Only supported on Linux, must be enabled in your kernel.
|
||||
# See: <https://qdrant.tech/articles/io_uring/#and-what-about-qdrant>
|
||||
#async_scorer: false
|
||||
|
||||
optimizers:
|
||||
# The minimal fraction of deleted vectors in a segment, required to perform segment optimization
|
||||
deleted_threshold: 0.2
|
||||
|
||||
# The minimal number of vectors in a segment, required to perform segment optimization
|
||||
vacuum_min_vector_number: 1000
|
||||
|
||||
# Target amount of segments optimizer will try to keep.
|
||||
# Real amount of segments may vary depending on multiple parameters:
|
||||
# - Amount of stored points
|
||||
# - Current write RPS
|
||||
#
|
||||
# It is recommended to select default number of segments as a factor of the number of search threads,
|
||||
# so that each segment would be handled evenly by one of the threads.
|
||||
# If `default_segment_number = 0`, will be automatically selected by the number of available CPUs
|
||||
default_segment_number: 0
|
||||
|
||||
# Do not create segments larger this size (in KiloBytes).
|
||||
# Large segments might require disproportionately long indexation times,
|
||||
# therefore it makes sense to limit the size of segments.
|
||||
#
|
||||
# If indexation speed have more priority for your - make this parameter lower.
|
||||
# If search speed is more important - make this parameter higher.
|
||||
# Note: 1Kb = 1 vector of size 256
|
||||
# If not set, will be automatically selected considering the number of available CPUs.
|
||||
max_segment_size_kb: null
|
||||
|
||||
# Maximum size (in KiloBytes) of vectors to store in-memory per segment.
|
||||
# Segments larger than this threshold will be stored as read-only memmapped file.
|
||||
# To enable memmap storage, lower the threshold
|
||||
# Note: 1Kb = 1 vector of size 256
|
||||
# To explicitly disable mmap optimization, set to `0`.
|
||||
# If not set, will be disabled by default.
|
||||
memmap_threshold_kb: null
|
||||
|
||||
# Maximum size (in KiloBytes) of vectors allowed for plain index.
|
||||
# Default value based on https://github.com/google-research/google-research/blob/master/scann/docs/algorithms.md
|
||||
# Note: 1Kb = 1 vector of size 256
|
||||
# To explicitly disable vector indexing, set to `0`.
|
||||
# If not set, the default value will be used.
|
||||
indexing_threshold_kb: 20000
|
||||
|
||||
# Interval between forced flushes.
|
||||
flush_interval_sec: 5
|
||||
|
||||
# Max number of threads (jobs) for running optimizations per shard.
|
||||
# Note: each optimization job will also use `max_indexing_threads` threads by itself for index building.
|
||||
# If null - have no limit and choose dynamically to saturate CPU.
|
||||
# If 0 - no optimization threads, optimizations will be disabled.
|
||||
max_optimization_threads: null
|
||||
|
||||
# This section has the same options as 'optimizers' above. All values specified here will overwrite the collections
|
||||
# optimizers configs regardless of the config above and the options specified at collection creation.
|
||||
#optimizers_overwrite:
|
||||
# deleted_threshold: 0.2
|
||||
# vacuum_min_vector_number: 1000
|
||||
# default_segment_number: 0
|
||||
# max_segment_size_kb: null
|
||||
# memmap_threshold_kb: null
|
||||
# indexing_threshold_kb: 20000
|
||||
# flush_interval_sec: 5
|
||||
# max_optimization_threads: null
|
||||
|
||||
# Default parameters of HNSW Index. Could be overridden for each collection or named vector individually
|
||||
hnsw_index:
|
||||
# Number of edges per node in the index graph. Larger the value - more accurate the search, more space required.
|
||||
m: 16
|
||||
|
||||
# Number of neighbours to consider during the index building. Larger the value - more accurate the search, more time required to build index.
|
||||
ef_construct: 100
|
||||
|
||||
# Minimal size (in KiloBytes) of vectors for additional payload-based indexing.
|
||||
# If payload chunk is smaller than `full_scan_threshold_kb` additional indexing won't be used -
|
||||
# in this case full-scan search should be preferred by query planner and additional indexing is not required.
|
||||
# Note: 1Kb = 1 vector of size 256
|
||||
full_scan_threshold_kb: 10000
|
||||
|
||||
# Number of parallel threads used for background index building.
|
||||
# If 0 - automatically select.
|
||||
# Best to keep between 8 and 16 to prevent likelihood of building broken/inefficient HNSW graphs.
|
||||
# On small CPUs, less threads are used.
|
||||
max_indexing_threads: 0
|
||||
|
||||
# Store HNSW index on disk. If set to false, index will be stored in RAM. Default: false
|
||||
on_disk: false
|
||||
|
||||
# Custom M param for hnsw graph built for payload index. If not set, default M will be used.
|
||||
payload_m: null
|
||||
|
||||
# Default shard transfer method to use if none is defined.
|
||||
# If null - don't have a shard transfer preference, choose automatically.
|
||||
# If stream_records, snapshot or wal_delta - prefer this specific method.
|
||||
# More info: https://qdrant.tech/documentation/guides/distributed_deployment/#shard-transfer-method
|
||||
shard_transfer_method: null
|
||||
|
||||
# Default parameters for collections
|
||||
collection:
|
||||
# Number of replicas of each shard that network tries to maintain
|
||||
replication_factor: 1
|
||||
|
||||
# How many replicas should apply the operation for us to consider it successful
|
||||
write_consistency_factor: 1
|
||||
|
||||
# Default parameters for vectors.
|
||||
vectors:
|
||||
# Whether vectors should be stored in memory or on disk.
|
||||
on_disk: null
|
||||
|
||||
# shard_number_per_node: 1
|
||||
|
||||
# Default quantization configuration.
|
||||
# More info: https://qdrant.tech/documentation/guides/quantization
|
||||
quantization: null
|
||||
|
||||
# Default strict mode parameters for newly created collections.
|
||||
strict_mode:
|
||||
# Whether strict mode is enabled for a collection or not.
|
||||
enabled: false
|
||||
|
||||
# Max allowed `limit` parameter for all APIs that don't have their own max limit.
|
||||
max_query_limit: null
|
||||
|
||||
# Max allowed `timeout` parameter.
|
||||
max_timeout: null
|
||||
|
||||
# Allow usage of unindexed fields in retrieval based (eg. search) filters.
|
||||
unindexed_filtering_retrieve: null
|
||||
|
||||
# Allow usage of unindexed fields in filtered updates (eg. delete by payload).
|
||||
unindexed_filtering_update: null
|
||||
|
||||
# Max HNSW value allowed in search parameters.
|
||||
search_max_hnsw_ef: null
|
||||
|
||||
# Whether exact search is allowed or not.
|
||||
search_allow_exact: null
|
||||
|
||||
# Max oversampling value allowed in search.
|
||||
search_max_oversampling: null
|
||||
|
||||
service:
|
||||
# Maximum size of POST data in a single request in megabytes
|
||||
max_request_size_mb: 32
|
||||
|
||||
# Number of parallel workers used for serving the api. If 0 - equal to the number of available cores.
|
||||
# If missing - Same as storage.max_search_threads
|
||||
max_workers: 0
|
||||
|
||||
# Host to bind the service on
|
||||
host: 0.0.0.0
|
||||
|
||||
# HTTP(S) port to bind the service on
|
||||
http_port: 6333
|
||||
|
||||
# gRPC port to bind the service on.
|
||||
# If `null` - gRPC is disabled. Default: null
|
||||
# Comment to disable gRPC:
|
||||
grpc_port: 6334
|
||||
|
||||
# Enable CORS headers in REST API.
|
||||
# If enabled, browsers would be allowed to query REST endpoints regardless of query origin.
|
||||
# More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
|
||||
# Default: true
|
||||
enable_cors: true
|
||||
|
||||
# Enable HTTPS for the REST and gRPC API
|
||||
enable_tls: false
|
||||
|
||||
# Check user HTTPS client certificate against CA file specified in tls config
|
||||
verify_https_client_certificate: false
|
||||
|
||||
# Set an api-key.
|
||||
# If set, all requests must include a header with the api-key.
|
||||
# example header: `api-key: <API-KEY>`
|
||||
#
|
||||
# If you enable this you should also enable TLS.
|
||||
# (Either above or via an external service like nginx.)
|
||||
# Sending an api-key over an unencrypted channel is insecure.
|
||||
#
|
||||
# Uncomment to enable.
|
||||
# api_key: your_secret_api_key_here
|
||||
|
||||
# Set an api-key for read-only operations.
|
||||
# If set, all requests must include a header with the api-key.
|
||||
# example header: `api-key: <API-KEY>`
|
||||
#
|
||||
# If you enable this you should also enable TLS.
|
||||
# (Either above or via an external service like nginx.)
|
||||
# Sending an api-key over an unencrypted channel is insecure.
|
||||
#
|
||||
# Uncomment to enable.
|
||||
# read_only_api_key: your_secret_read_only_api_key_here
|
||||
|
||||
# Uncomment to enable JWT Role Based Access Control (RBAC).
|
||||
# If enabled, you can generate JWT tokens with fine-grained rules for access control.
|
||||
# Use generated token instead of API key.
|
||||
#
|
||||
# jwt_rbac: true
|
||||
|
||||
# Hardware reporting adds information to the API responses with a
|
||||
# hint on how many resources were used to execute the request.
|
||||
#
|
||||
# Uncomment to enable.
|
||||
# hardware_reporting: true
|
||||
|
||||
cluster:
|
||||
# Use `enabled: true` to run Qdrant in distributed deployment mode
|
||||
enabled: false
|
||||
|
||||
# Configuration of the inter-cluster communication
|
||||
p2p:
|
||||
# Port for internal communication between peers
|
||||
port: 6335
|
||||
|
||||
# Use TLS for communication between peers
|
||||
enable_tls: false
|
||||
|
||||
# Configuration related to distributed consensus algorithm
|
||||
consensus:
|
||||
# How frequently peers should ping each other.
|
||||
# Setting this parameter to lower value will allow consensus
|
||||
# to detect disconnected nodes earlier, but too frequent
|
||||
# tick period may create significant network and CPU overhead.
|
||||
# We encourage you NOT to change this parameter unless you know what you are doing.
|
||||
tick_period_ms: 100
|
||||
|
||||
# Compact consensus operations once we have this amount of applied
|
||||
# operations. Allows peers to join quickly with a consensus snapshot without
|
||||
# replaying a huge amount of operations.
|
||||
# If 0 - disable compaction
|
||||
compact_wal_entries: 128
|
||||
|
||||
# Set to true to prevent service from sending usage statistics to the developers.
|
||||
# Read more: https://qdrant.tech/documentation/guides/telemetry
|
||||
telemetry_disabled: true
|
313
AGENTS.md
Normal file
313
AGENTS.md
Normal file
@@ -0,0 +1,313 @@
|
||||
# PhotoPrism® Repository Guidelines
|
||||
|
||||
## Purpose
|
||||
|
||||
This file tells automated coding agents (and humans) where to find the single sources of truth for building, testing, and contributing to PhotoPrism.
|
||||
Learn more: https://agents.md/
|
||||
|
||||
## Sources of Truth
|
||||
|
||||
- Makefile targets (always prefer existing targets): https://github.com/photoprism/photoprism/blob/develop/Makefile
|
||||
- Developer Guide – Setup: https://docs.photoprism.app/developer-guide/setup/
|
||||
- Developer Guide – Tests: https://docs.photoprism.app/developer-guide/tests/
|
||||
- Contributing: https://github.com/photoprism/photoprism/blob/develop/CONTRIBUTING.md
|
||||
- Security: https://github.com/photoprism/photoprism/blob/develop/SECURITY.md
|
||||
- REST API: https://docs.photoprism.dev/ (Swagger), https://docs.photoprism.app/developer-guide/api/ (Docs)
|
||||
- Backend CODEMAP: CODEMAP.md
|
||||
- Frontend CODEMAP: frontend/CODEMAP.md
|
||||
|
||||
### Specifications (Versioning & Usage)
|
||||
|
||||
- Always use the latest spec version for a topic (highest `-vN`), as linked from `specs/README.md` and the portal cheatsheet (`specs/portal/README.md`).
|
||||
- Older spec versions remain in the repo for historical reference but are not linked from the main TOC. Do not base new work on superseded files (e.g., `*-v1.md` when `*-v2.md` exists).
|
||||
- When adding or updating specs, publish changes under a new file with an incremented version suffix (e.g., `*-v3.md`) instead of overwriting. Refer to the Change Management section of each document for specific instructions.
|
||||
- Developer Cheatsheet – Portal & Cluster: specs/portal/README.md
|
||||
- Backend (Go) Testing Guide: specs/dev/backend-testing.md
|
||||
|
||||
## Project Structure & Languages
|
||||
|
||||
- Backend: Go (`internal/`, `pkg/`, `cmd/`) + MariaDB/SQLite
|
||||
- Package boundaries: Code in `pkg/*` MUST NOT import from `internal/*`.
|
||||
- If you need access to config/entity/DB, put new code in a package under `internal/` instead of `pkg/`.
|
||||
- Frontend: Vue 3 + Vuetify 3 (`frontend/`)
|
||||
- Docker/compose for dev/CI; Traefik is used for local TLS (`*.localssl.dev`)
|
||||
|
||||
## Agent Runtime (Host vs Container)
|
||||
|
||||
Agents MAY run either:
|
||||
|
||||
- **Inside the Development Environment container** (recommended for least privilege).
|
||||
- **On the host** (outside Docker), in which case the agent MAY start/stop the Dev Environment as needed.
|
||||
|
||||
### Detecting the environment (agent logic)
|
||||
|
||||
Agents SHOULD detect the runtime and choose commands accordingly:
|
||||
|
||||
- **Inside container if** one of the following is true:
|
||||
- File exists: `/.dockerenv`
|
||||
- Project path equals (or is a direct child of): `/go/src/github.com/photoprism/photoprism`
|
||||
|
||||
#### Examples
|
||||
|
||||
Bash:
|
||||
|
||||
```bash
|
||||
if [ -f "/.dockerenv" ] || [ -d "/go/src/github.com/photoprism/photoprism/.git" ]; then
|
||||
echo "container"
|
||||
else
|
||||
echo "host"
|
||||
fi
|
||||
```
|
||||
|
||||
Node.js:
|
||||
|
||||
```js
|
||||
const fs = require("fs");
|
||||
const inContainer = fs.existsSync("/.dockerenv");
|
||||
const inDevPath = fs.existsSync("/go/src/github.com/photoprism/photoprism/.git");
|
||||
console.log(inContainer || inDevPath ? "container" : "host");
|
||||
```
|
||||
|
||||
### Agent installation and invocation
|
||||
|
||||
- **Inside container**: Prefer running agents via `npm exec` (no global install), for example:
|
||||
- `npm exec --yes <agent-binary> -- --help`
|
||||
- Or use `npx <agent-binary> ...`
|
||||
- If the agent is distributed via npm and must be global, install inside the container only:
|
||||
- `npm install -g <agent-npm-package>`
|
||||
- Replace `<agent-binary>` / `<agent-npm-package>` with the names from the agent’s official docs.
|
||||
|
||||
- **On host**: Use the vendor’s recommended install for your OS. Ensure your agent runs from the repository root so it can discover `AGENTS.md` and project files.
|
||||
|
||||
## Build & Run (local)
|
||||
|
||||
- Run `make help` to see common targets (or open the `Makefile`).
|
||||
|
||||
- **Host mode** (agent runs on the host; agent MAY manage Docker lifecycle):
|
||||
- Build local dev image (once): `make docker-build`
|
||||
- Start services: `docker compose up` (add `-d` to start in the background)
|
||||
- Follow live app logs: `docker compose logs -f --tail=100 photoprism` (Ctrl+C to stop)
|
||||
- All services: `docker compose logs -f --tail=100`
|
||||
- Last 10 minutes only: `docker compose logs -f --since=10m photoprism`
|
||||
- Plain output (easier to copy): `docker compose logs -f --no-log-prefix --no-color photoprism`
|
||||
- Execute a single command in the app container: `docker compose exec photoprism <command>`
|
||||
- Example: `docker compose exec photoprism ./photoprism help`
|
||||
- Why `./photoprism`? It runs the locally built binary in the project directory.
|
||||
- Run as non-root to avoid root-owned files on bind mounts:
|
||||
`docker compose exec -u "$(id -u):$(id -g)" photoprism <command>`
|
||||
- Durable alternative: set the service user or `PHOTOPRISM_UID`/`PHOTOPRISM_GID` in `compose.yaml`; if you hit issues, run `make fix-permissions`.
|
||||
- Open a terminal session in the app container: `make terminal`
|
||||
- Stop everything when done: `docker compose --profile=all down --remove-orphans` (`make down` does the same)
|
||||
|
||||
- **Container mode** (agent runs inside the app container):
|
||||
- Install deps: `make dep`
|
||||
- Build frontend/backend: `make build-js` and `make build-go`
|
||||
- Watch frontend changes (auto-rebuild): `make watch-js`
|
||||
- Or run directly: `cd frontend && npm run watch`
|
||||
- Tips: refresh the browser to see changes; running the watcher outside the container can be faster on non-Linux hosts; stop with Ctrl+C
|
||||
- Start the PhotoPrism server: `./photoprism start`
|
||||
- Open http://localhost:2342/ (HTTP)
|
||||
- Or https://app.localssl.dev/ (HTTPS via Traefik reverse proxy)
|
||||
- Only if Traefik is running and the dev compose labels are active
|
||||
- Labels for `*.localssl.dev` are defined in the dev compose files, e.g. https://github.com/photoprism/photoprism/blob/develop/compose.yaml
|
||||
- Do not use the Docker CLI inside the container; starting/stopping services requires host Docker access.
|
||||
|
||||
Note: Across our public documentation, official images, and in production, the command-line interface (CLI) name is `photoprism`. Other PhotoPrism binary names are only used in development builds for side-by-side comparisons of the Community Edition (CE) with PhotoPrism Plus (`photoprism-plus`) and PhotoPrism Pro (`photoprism-pro`).
|
||||
|
||||
## Tests
|
||||
|
||||
- From within the Development Environment:
|
||||
- Full unit test suite: `make test` (runs backend and frontend tests)
|
||||
- Test frontend/backend: `make test-js` and `make test-go`
|
||||
- Go packages: `go test` (all tests) or `go test -run <name>` (specific tests only)
|
||||
- Frontend unit tests are driven by Vitest; see scripts in `frontend/package.json`
|
||||
- Vitest watch/coverage: `make vitest-watch` and `make vitest-coverage`
|
||||
- Acceptance tests: use the `acceptance-*` targets in the `Makefile`
|
||||
|
||||
### CLI Testing Gotchas (Go)
|
||||
|
||||
- Exit codes and `os.Exit`:
|
||||
- `urfave/cli` calls `os.Exit(code)` when a command returns `cli.Exit(...)`, which will terminate `go test` abruptly (often after logs like `http 401:`).
|
||||
- Use the test helper `RunWithTestContext` (in `internal/commands/commands_test.go`) which temporarily overrides `cli.OsExiter` so the process doesn’t exit; you still receive the error to assert `ExitCoder`.
|
||||
- If you only need to assert the exit code and don’t need printed output, you can invoke `cmd.Action(ctx)` directly and check `err.(cli.ExitCoder).ExitCode()`.
|
||||
- Non‑interactive mode: set `PHOTOPRISM_CLI=noninteractive` and/or pass `--yes` to avoid prompts that block tests and CI.
|
||||
- SQLite DSN in tests:
|
||||
- `config.NewTestConfig("<pkg>")` defaults to SQLite with a per‑suite DSN like `.<pkg>.db`. Don’t assert an empty DSN for SQLite.
|
||||
- Clean up any per‑suite SQLite files in tests with `t.Cleanup(func(){ _ = os.Remove(dsn) })` if you capture the DSN.
|
||||
|
||||
## Code Style & Lint
|
||||
|
||||
- Go: run `make fmt-go swag-fmt` to reformat the backend code + Swagger annotations (see `Makefile` for additional targets)
|
||||
- Doc comments for packages and exported identifiers must be complete sentences that begin with the name of the thing being described and end with a period.
|
||||
- For short examples inside comments, indent code rather than using backticks; godoc treats indented blocks as preformatted.
|
||||
- JS/Vue: use the lint/format scripts in `frontend/package.json` (ESLint + Prettier)
|
||||
- All added code and tests **must** be formatted according to our standards.
|
||||
|
||||
## Safety & Data
|
||||
|
||||
- Never commit secrets, local configurations, or cache files. Use environment variables or a local `.env`.
|
||||
- Ensure `.env` and `.local` are ignored in `.gitignore` and `.dockerignore`.
|
||||
- Prefer using existing caches, workers, and batching strategies referenced in code and `Makefile`. Consider memory/CPU impact; suggest benchmarks or profiling only when justified.
|
||||
- Do not run destructive commands against production data. Prefer ephemeral volumes and test fixtures when running acceptance tests.
|
||||
- Examples assume a Linux/Unix shell. For Windows specifics, see the Developer Guide FAQ:
|
||||
https://docs.photoprism.app/developer-guide/faq/#can-your-development-environment-be-used-under-windows
|
||||
|
||||
If anything in this file conflicts with the `Makefile` or the Developer Guide, the `Makefile` and the documentation win. When unsure, **ask** for clarification before proceeding.
|
||||
|
||||
## Agent Quick Tips (Do This)
|
||||
|
||||
### Testing
|
||||
|
||||
- Prefer targeted runs for speed:
|
||||
- Unit/subpackage: `go test ./internal/<pkg> -run <Name> -count=1`
|
||||
- Commands: `go test ./internal/commands -run <Name> -count=1`
|
||||
- Avoid `./...` unless you intend to run the whole suite.
|
||||
- Heavy tests (migrations/fixtures): internal/entity and internal/photoprism run DB migrations and load fixtures; expect 30–120s on first run. Narrow with `-run` and keep iterations low.
|
||||
- PhotoPrism config in tests: inside `internal/photoprism`, use the package global `photoprism.Config()` for runtime‑accurate behavior. Only construct a new config if you replace it via `photoprism.SetConfig`.
|
||||
- CLI command tests: use `RunWithTestContext(cmd, args)` to capture output and avoid `os.Exit`; assert `cli.ExitCoder` codes when you need them.
|
||||
- Reports are quoted: strings in CLI "show" output are rendered with quotes by the report helpers. Prefer `assert.Contains`/regex over strict, fully formatted equality when validating content.
|
||||
|
||||
### Roles & ACL
|
||||
|
||||
- Always map roles via the central tables:
|
||||
- Users: `acl.ParseRole(s)` or `acl.UserRoles[clean.Role(s)]`.
|
||||
- Clients: `acl.ClientRoles[clean.Role(s)]`.
|
||||
- Aliases: `RoleAliasNone` ("none") and the empty string both map to `RoleNone`; do not special‑case them in callers.
|
||||
- Defaults:
|
||||
- Client roles: if input is unknown, default to `RoleClient`.
|
||||
- User roles: `acl.ParseRole` handles special tokens like `0/false/nil` as none.
|
||||
- CLI usage strings: build flag help from `Roles.CliUsageString()` (e.g., `acl.ClientRoles.CliUsageString()`), not from hard‑coded lists.
|
||||
|
||||
### Import/Index
|
||||
|
||||
- ImportWorker may skip files if an identical file already exists (duplicate detection). Use unique copies or assert DB rows after ensuring a non‑duplicate destination.
|
||||
- Mixed roots: when testing related files, keep `ExamplesPath()/ImportPath()/OriginalsPath()` consistent so `RelatedFiles` and `AllowExt` behave as expected.
|
||||
|
||||
### CLI Usage & Assertions
|
||||
|
||||
- Capture output with `RunWithTestContext`; usage and report values may be quoted and re‑ordered (e.g., set semantics). Use substring checks or regex for the final ", or <last>" rule from `CliUsageString`.
|
||||
- Prefer JSON output (`--json`) for stable machine assertions when commands offer it.
|
||||
|
||||
### API Development & Config Options
|
||||
|
||||
The following conventions summarize the insights gained when adding new configuration options, API endpoints, and related tests. Follow these conventions unless a maintainer requests an exception.
|
||||
|
||||
- Config precedence and new options
|
||||
- Global precedence: If present, values in `options.yml` override CLI flags and environment variables; all override config defaults in `defaults.yml`. Don’t special‑case a single option.
|
||||
- Adding a new option:
|
||||
- Add a field to `internal/config/options.go` with `yaml:"…"` and a `flag:"…"` tag.
|
||||
- Register a CLI flag and env mapping in `internal/config/flags.go` (use `EnvVars(...)`).
|
||||
- Expose a getter on `*config.Config` in the relevant file (e.g., cluster options in `config_cluster.go`).
|
||||
- Add name/value to `rows` in `*config.Report()`, after the same option as in `internal/config/options.go` for `photoprism show config` to report it (obfuscate passwords with `*`).
|
||||
- If the value must persist (e.g., a generated UUID), write it back to `options.yml` using a focused helper that merges keys.
|
||||
- Tests: cover CLI/env/file precedence and persistence. When tests need a new flag, add it to `CliTestContext` in `internal/config/test.go`.
|
||||
- Example: `ClusterUUID` precedence = `options.yml` → CLI/env (`--cluster-uuid` / `PHOTOPRISM_CLUSTER_UUID`) → generate UUIDv4 and persist.
|
||||
- CLI flag precedence: when you need to favor an explicit CLI flag over defaults, check `c.cliCtx.IsSet("<flag>")` before applying additional precedence logic.
|
||||
- Persisting generated options: when writing to `options.yml`, set `c.options.OptionsYaml = filepath.Join(c.ConfigPath(), "options.yml")` and reload the file to keep in‑memory
|
||||
|
||||
- Database access
|
||||
- The app uses GORM v1. Don’t use `WithContext`; for executing raw SQL, prefer `db.Raw(stmt).Scan(&nop)`.
|
||||
- When provisioning MariaDB/MySQL objects, quote identifiers with backticks and limit the character set; avoid building identifiers from untrusted input.
|
||||
- Reuse `conf.Db()` and `conf.Database*()` getters; reject unsupported drivers early with a clear error.
|
||||
|
||||
- Rate limiting
|
||||
- Reuse the existing limiter in `internal/server/limiter` (e.g., `limiter.Auth` / `limiter.Login`).
|
||||
- For 429s, use `limiter.AbortJSON(c)` when applicable; avoid creating new limiter stacks.
|
||||
|
||||
- API handlers
|
||||
- Use existing helpers: `api.ClientIP(c)`, `header.BearerToken(c)`, `Abort*` functions for errors.
|
||||
- Compare secrets/tokens using constant‑time compare; don’t log secrets.
|
||||
- Set `Cache-Control: no-store` on responses containing secrets.
|
||||
- Register new routes in `internal/server/routes.go`. Don’t edit `swagger.json` directly—run `make swag` to regenerate.
|
||||
- Portal mode: set `PHOTOPRISM_NODE_ROLE=portal` and `PHOTOPRISM_JOIN_TOKEN`.
|
||||
- Pagination defaults: for new list endpoints, prefer `count` default 100 (max 1000) and `offset` ≥ 0; document both in Swagger and validate bounds in handlers.
|
||||
- Document parameters explicitly in Swagger annotations (path, query, and body) so `make swag` produces accurate docs.
|
||||
- Swagger: `make fmt-go swag-fmt && make swag` after adding or changing API annotations.
|
||||
- Focused tests: `go test ./internal/api -run Cluster -count=1` (or limit to the package you changed).
|
||||
|
||||
- Registry & secrets
|
||||
- Store portal/node registry data under `conf.PortalConfigPath()/nodes/` as YAML with file mode `0600`.
|
||||
- Keep node secrets out of logs and omit them from JSON responses unless explicitly returned on creation/rotation.
|
||||
|
||||
- Testing patterns
|
||||
- Use `t.TempDir()` for isolated config paths and files. After changing `ConfigPath` post‑construction, reload `options.yml` into `c.options` if needed.
|
||||
- Prefer small, focused unit tests; use existing test helpers (`NewConfig`, `CliTestContext`, etc.).
|
||||
- API tests: use `NewApiTest()`, `PerformRequest*`, `AuthenticateAdmin` / `AuthenticateUser`, and `OAuthToken` for client-scope scenarios.
|
||||
- Permissions: cover public=false (401), CDN headers (403), admin access (200), and client tokens with insufficient scope (403).
|
||||
- Auth mode in tests: use `conf.SetAuthMode(config.AuthModePasswd)` (and defer restore) instead of flipping `Options().Public`; this toggles related internals used by tests.
|
||||
- Fixtures caveat: user fixtures often have admin role; for negative permission tests, prefer OAuth client tokens with limited scope rather than relying on a non‑admin user.
|
||||
|
||||
### Formatting (Go)
|
||||
|
||||
- Go is formatted by `gofmt` and uses tabs. Do not hand-format indentation.
|
||||
- Always run after edits: `make fmt-go` (gofmt + goimports).
|
||||
|
||||
### API Shape Checklist
|
||||
|
||||
- When renaming or adding fields:
|
||||
- Update DTOs in `internal/service/cluster/response.go` and any mappers.
|
||||
- Update handlers and regenerate Swagger: `make fmt-go swag-fmt swag`.
|
||||
- Update tests (search/replace old field names) and examples in `specs/`.
|
||||
- Quick grep: `rg -n 'oldField|newField' -S` across code, tests, and specs.
|
||||
|
||||
### Cluster Registry (Source of Truth)
|
||||
|
||||
- Use the client‑backed registry (`NewClientRegistryWithConfig`).
|
||||
- The file‑backed registry is historical; do not add new references to it.
|
||||
- Migration “done” checklist: swap callsites → build → API tests → CLI tests → remove legacy references.
|
||||
|
||||
### API/CLI Tests: Known Pitfalls
|
||||
|
||||
- Gin routes: Register `CreateSession(router)` once per test router; reusing it twice panics on duplicate route.
|
||||
- CLI commands: Some commands defer `conf.Shutdown()` or emit signals that close the DB. The harness re‑opens DB before each run, but avoid invoking `start` or emitting signals in unit tests.
|
||||
- Signals: `internal/commands/start.go` waits on `process.Signal`; calling `process.Shutdown()/Restart()` can close DB. Prefer not to trigger signals in tests.
|
||||
|
||||
### Sessions & Redaction (building sessions in tests)
|
||||
|
||||
- Admin session (full view): `AuthenticateAdmin(app, router)`.
|
||||
- User session: Create a non‑admin test user (role=guest), set a password, then `AuthenticateUser`.
|
||||
- Client session (redacted internal fields; `siteUrl` visible):
|
||||
```go
|
||||
s, _ := entity.AddClientSession("test-client", conf.SessionMaxAge(), "cluster", authn.GrantClientCredentials, nil)
|
||||
token := s.AuthToken()
|
||||
r := AuthenticatedRequest(app, http.MethodGet, "/api/v1/cluster/nodes", token)
|
||||
```
|
||||
Admins see `advertiseUrl` and `database`; client/user sessions don’t. `siteUrl` is safe to show to all roles.
|
||||
|
||||
### Preflight Checklist
|
||||
|
||||
- `go build ./...`
|
||||
- `make fmt-go swag-fmt swag`
|
||||
- `go test ./internal/service/cluster/registry -count=1`
|
||||
- `go test ./internal/api -run 'Cluster' -count=1`
|
||||
- `go test ./internal/commands -run 'ClusterRegister|ClusterNodesRotate' -count=1`
|
||||
|
||||
- Known tooling constraints
|
||||
- Python may not be available in the dev container; prefer `apply_patch`, Go, or Make targets over ad‑hoc scripts.
|
||||
- `make swag` may fetch modules; ensure network availability in CI before running.
|
||||
|
||||
### Cluster Config & Bootstrap
|
||||
|
||||
- Import rules (avoid cycles):
|
||||
- Do not import `internal/service/cluster/instance/*` from `internal/config` or the cluster root package.
|
||||
- Instance/service bootstraps talk to the Portal via HTTP(S); do not import Portal internals such as `internal/api` or `internal/service/cluster/registry`/`provisioner`.
|
||||
- Prefer constants from `internal/service/cluster/const.go` (e.g., `cluster.RoleInstance`, `cluster.RolePortal`) over string literals.
|
||||
|
||||
- Early extension lifecycle (config.Init sequence):
|
||||
1) Load `options.yml` and settings (`c.initSettings()`)
|
||||
2) Run early hooks: `EarlyExt().InitEarly(c)` (may adjust DB settings)
|
||||
3) Connect DB: `connectDb()` and `RegisterDb()`
|
||||
4) Run regular extensions: `Ext().Init(c)`
|
||||
|
||||
- Theme endpoint usage:
|
||||
- Server: `GET /api/v1/cluster/theme` generates a zip from `conf.ThemePath()`; returns 200 with a valid (possibly empty) zip or 404 if missing.
|
||||
- Client/CLI: install only if `ThemePath()` is missing or lacks `app.js`; do not overwrite unless explicitly allowed.
|
||||
- Use header helpers/constants from `pkg/service/http/header` (e.g., `header.Accept`, `header.ContentTypeZip`, `header.SetAuthorization`).
|
||||
|
||||
- Registration (instance bootstrap):
|
||||
- Send `rotate=true` only if driver is MySQL/MariaDB and no DSN/name/user/password is configured (including *_FILE for password); never for SQLite.
|
||||
- Treat 401/403/404 as terminal; apply bounded retries with delay for transient/network/429.
|
||||
- Persist only missing `NodeSecret` and DB settings when rotation was requested.
|
||||
|
||||
- Testing patterns:
|
||||
- Use `httptest` for Portal endpoints and `pkg/fs.Unzip` with size caps for extraction tests.
|
171
CODEMAP.md
Normal file
171
CODEMAP.md
Normal file
@@ -0,0 +1,171 @@
|
||||
PhotoPrism — Backend CODEMAP
|
||||
|
||||
Purpose
|
||||
- Give agents and contributors a fast, reliable map of where things live and how they fit together, so you can add features, fix bugs, and write tests without spelunking.
|
||||
- Sources of truth: prefer Makefile targets and the Developer Guide linked in AGENTS.md.
|
||||
|
||||
Quick Start
|
||||
- Inside dev container (recommended):
|
||||
- Install deps: `make dep`
|
||||
- Build backend: `make build-go`
|
||||
- Run server: `./photoprism start`
|
||||
- Open: http://localhost:2342/ or https://app.localssl.dev/ (Traefik required)
|
||||
- On host (manages Docker):
|
||||
- Build image: `make docker-build`
|
||||
- Start services: `docker compose up -d`
|
||||
- Logs: `docker compose logs -f --tail=100 photoprism`
|
||||
|
||||
Executables & Entry Points
|
||||
- CLI app (binary name across docs/images is `photoprism`):
|
||||
- Main: `cmd/photoprism/photoprism.go`
|
||||
- Commands registry: `internal/commands/commands.go` (array `commands.PhotoPrism`)
|
||||
- Web server:
|
||||
- Startup: `internal/commands/start.go` → `server.Start` (starts HTTP(S), workers, session cleanup)
|
||||
- HTTP server: `internal/server/start.go` (compression, security, healthz, readiness, TLS/AutoTLS/unix socket)
|
||||
- Routes: `internal/server/routes.go` (registers all v1 API groups + UI, WebDAV, sharing, .well-known)
|
||||
- API group: `APIv1 = router.Group(conf.BaseUri("/api/v1"), Api(conf))`
|
||||
|
||||
High-Level Package Map (Go)
|
||||
- `internal/api` — Gin handlers and Swagger annotations; only glue, no business logic
|
||||
- `internal/server` — HTTP server, middleware, routing, static/ui/webdav
|
||||
- `internal/config` — configuration, flags/env/options, client config, DB init/migrate
|
||||
- `internal/entity` — GORM v1 models, queries, search helpers, migrations
|
||||
- `internal/photoprism` — core domain logic (indexing, import, faces, thumbnails, cleanup)
|
||||
- `internal/workers` — background schedulers (index, vision, sync, meta, backup)
|
||||
- `internal/auth` — ACL, sessions, OIDC
|
||||
- `internal/service` — cluster/portal, maps, hub, webdav
|
||||
- `internal/event` — logging, pub/sub, audit
|
||||
- `internal/ffmpeg`, `internal/thumb`, `internal/meta`, `internal/form`, `internal/mutex` — media, thumbs, metadata, forms, coordination
|
||||
- `pkg/*` — reusable utilities (must never import from `internal/*`), e.g. `pkg/fs`, `pkg/log`, `pkg/service/http/header`
|
||||
|
||||
HTTP API
|
||||
- Handlers live in `internal/api/*.go` and are registered in `internal/server/routes.go`.
|
||||
- Annotate new endpoints in handler files; generate docs with: `make fmt-go swag-fmt && make swag`.
|
||||
- Do not edit `internal/api/swagger.json` by hand.
|
||||
- Common groups in `routes.go`: sessions, OAuth/OIDC, config, users, services, thumbnails, video, downloads/zip, index/import, photos/files/labels/subjects/faces, batch ops, cluster, technical (metrics, status, echo).
|
||||
|
||||
Configuration & Flags
|
||||
- Options struct: `internal/config/options.go` with `yaml:"…"` (for `defaults.yml`/`options.yml`), `json:"…"` (clients/API), and `flag:"…"` (CLI flags/env) tags.
|
||||
- For secrets/internals: `json:"-"` disables JSON processing to prevent values from being exposed through the API (see `internal/api/config_options.go`).
|
||||
- If needed: `yaml:"-"` disables YAML processing; `flag:"-"` prevents `ApplyCliContext()` from assigning CLI values (flags/env variables) to a field, without affecting the flags in `internal/config/flags.go`.
|
||||
- Annotations may include edition tags like `tags:"plus,pro"` to control visibility (see `internal/config/options_report.go` logic).
|
||||
- Global flags/env: `internal/config/flags.go` (`EnvVars(...)`)
|
||||
- Available flags/env: `internal/config/cli_flags_report.go` + `internal/config/report_sections.go` → surfaced by `photoprism show config-options --md`
|
||||
- YAML options mapping: `internal/config/options_report.go` + `internal/config/report_sections.go` → surfaced by `photoprism show config-yaml --md`
|
||||
- Report current values: `internal/config/report.go` → surfaced by `photoprism show config` (alias `photoprism config --md`).
|
||||
- Precedence: `defaults.yml` < CLI/env < `options.yml` (global options rule). See Agent Tips in `AGENTS.md`.
|
||||
- Getters are grouped by topic, e.g. DB in `internal/config/config_db.go`, server in `config_server.go`, TLS in `config_tls.go`, etc.
|
||||
- Client Config (read-only)
|
||||
- Endpoint: GET `/api/v1/config` (see `internal/api/api_client_config.go`).
|
||||
- Assembly: Built from `internal/config/client_config.go` (not a direct serialization of Options) plus extension values registered via `config.Register` in `internal/config/extensions.go`.
|
||||
- Updates: Back-end calls `UpdateClientConfig()` to publish "config.updated" over websockets after changes (see `internal/api/config_options.go` and `internal/api/config_settings.go`).
|
||||
- ACL/mode aware: Values are filtered by user/session and may differ for public vs. authenticated users.
|
||||
- Don’t expose secrets: Treat it as client-visible; avoid sensitive data. To add fields, extend client values via `config.Register` rather than exposing Options directly.
|
||||
- Refresh cadence: The web UI (non‑mobile) also polls for updates every 10 minutes via `$config.update()` in `frontend/src/app.js`, complementing the websocket push.
|
||||
|
||||
Database & Migrations
|
||||
- Driver: GORM v1 (`github.com/jinzhu/gorm`). No `WithContext`. Use `db.Raw(stmt).Scan(&nop)` for raw SQL.
|
||||
- Entities and helpers: `internal/entity/*.go` and subpackages (`query`, `search`, `sortby`).
|
||||
- Migrations engine: `internal/entity/migrate/*` — run via `config.MigrateDb()`; CLI: `photoprism migrate` / `photoprism migrations`.
|
||||
- DB init/migrate flow: `internal/config/config_db.go` chooses driver/DSN, sets `gorm:table_options`, then `entity.InitDb(migrate.Opt(...))`.
|
||||
|
||||
AuthN/Z & Sessions
|
||||
- Session model and cache: `internal/entity/auth_session*` and `internal/auth/session/*` (cleanup worker).
|
||||
- ACL: `internal/auth/acl/*` — roles, grants, scopes; use constants; avoid logging secrets, compare tokens constant‑time.
|
||||
- OIDC: `internal/auth/oidc/*`.
|
||||
|
||||
Media Processing
|
||||
- Thumbnails: `internal/thumb/*` and helpers in `internal/photoprism/mediafile_thumbs.go`.
|
||||
- Metadata: `internal/meta/*`.
|
||||
- FFmpeg integration: `internal/ffmpeg/*`.
|
||||
|
||||
Background Workers
|
||||
- Scheduler and workers: `internal/workers/*.go` (index, vision, meta, sync, backup, share); started from `internal/commands/start.go`.
|
||||
- Auto indexer: `internal/workers/auto/*`.
|
||||
|
||||
Cluster / Portal
|
||||
- Node types: `internal/service/cluster/const.go` (`cluster.RoleInstance`, `cluster.RolePortal`, `cluster.RoleService`).
|
||||
- Instance bootstrap & registration: `internal/service/cluster/instance/*` (HTTP to Portal; do not import Portal internals).
|
||||
- Registry/provisioner: `internal/service/cluster/registry/*`, `internal/service/cluster/provisioner/*`.
|
||||
- Theme endpoint (server): GET `/api/v1/cluster/theme`; client/CLI installs theme only if missing or no `app.js`.
|
||||
- See specs cheat sheet: `specs/portal/README.md`.
|
||||
|
||||
Logging & Events
|
||||
- Logger and event hub: `internal/event/*`; `event.Log` is the shared logger.
|
||||
- HTTP headers/constants: `pkg/service/http/header/*` — always prefer these in handlers and tests.
|
||||
|
||||
Server Startup Flow (happy path)
|
||||
1) `photoprism start` (CLI) → `internal/commands/start.go`
|
||||
2) Config init, DB init/migrate, session cleanup worker
|
||||
3) `internal/server/start.go` builds Gin engine, middleware, API group, templates
|
||||
4) `internal/server/routes.go` registers UI, WebDAV, sharing, well‑known, and all `/api/v1/*` routes
|
||||
5) Workers and auto‑index start; health endpoints `/livez`, `/readyz` available
|
||||
|
||||
Common How‑Tos
|
||||
- Add a CLI command
|
||||
- Create `internal/commands/<name>.go` with a `*cli.Command`
|
||||
- Add it to `PhotoPrism` in `internal/commands/commands.go`
|
||||
- Tests: prefer `RunWithTestContext` from `internal/commands/commands_test.go` to avoid `os.Exit`
|
||||
|
||||
- Add a REST endpoint
|
||||
- Create handler in `internal/api/<area>.go` with Swagger annotations
|
||||
- Register it in `internal/server/routes.go`
|
||||
- Use helpers: `api.ClientIP(c)`, `header.BearerToken(c)`, `Abort*` functions
|
||||
- Validate pagination bounds (default `count=100`, max `1000`, `offset>=0`) for list endpoints
|
||||
- Run `make fmt-go swag-fmt && make swag`; keep docs accurate
|
||||
- Tests: `go test ./internal/api -run <Name>` and focused helpers (`NewApiTest()`, `PerformRequest*`)
|
||||
|
||||
- Add a config option
|
||||
- Add field with tags to `internal/config/options.go`
|
||||
- Register CLI flag/env in `internal/config/flags.go` via `EnvVars(...)`
|
||||
- Expose a getter (e.g., in `config_server.go` or topic file)
|
||||
- Append to `rows` in `*config.Report()` after the same option as in `options.go`
|
||||
- If value must persist, write back to `options.yml` and reload into memory
|
||||
- Tests: cover CLI/env/file precedence (see `internal/config/test.go` helpers)
|
||||
|
||||
- Touch the DB schema
|
||||
- Use GORM auto-migration, or add a custom migration in `internal/entity/migrate/<dialect>/...` and run `go generate` or `make generate` (runs `go generate` for all packages)
|
||||
- Bump/review version gates in `migrate.Version` usage via `config_db.go`
|
||||
- Tests: run against SQLite by default; for MySQL cases, gate appropriately
|
||||
|
||||
Testing
|
||||
- Full suite: `make test` (frontend + backend). Backend only: `make test-go`.
|
||||
- Focused packages: `go test ./internal/<pkg> -run <Name>`.
|
||||
- CLI tests: `PHOTOPRISM_CLI=noninteractive` or pass `--yes` to avoid prompts; use `RunWithTestContext` to prevent `os.Exit`.
|
||||
- SQLite DSN in tests is per‑suite (not empty). Clean up files if you capture the DSN.
|
||||
- Frontend unit tests via Vitest are separate; see `frontend/CODEMAP.md`.
|
||||
|
||||
Performance & Limits
|
||||
- Prefer existing caches/workers/batching as per Makefile and code.
|
||||
- When adding list endpoints, default `count=100` (max `1000`); set `Cache-Control: no-store` for secrets.
|
||||
|
||||
Conventions & Rules of Thumb
|
||||
- Respect package boundaries: code in `pkg/*` must not import `internal/*`.
|
||||
- Prefer constants/helpers from `pkg/service/http/header` over string literals.
|
||||
- Never log secrets; compare tokens constant‑time.
|
||||
- Don’t import Portal internals from cluster instance/service bootstraps; use HTTP.
|
||||
- Prefer small, hermetic unit tests; isolate filesystem paths with `t.TempDir()` and env like `PHOTOPRISM_STORAGE_PATH`.
|
||||
|
||||
Frequently Touched Files (by topic)
|
||||
- CLI wiring: `cmd/photoprism/photoprism.go`, `internal/commands/commands.go`
|
||||
- Server: `internal/server/start.go`, `internal/server/routes.go`, middleware in `internal/server/*.go`
|
||||
- API handlers: `internal/api/*.go` (plus `docs.go` for package docs)
|
||||
- Config: `internal/config/*` (`flags.go`, `config_db.go`, `config_server.go`, `options.go`)
|
||||
- Entities & queries: `internal/entity/*.go`, `internal/entity/query/*`
|
||||
- Migrations: `internal/entity/migrate/*`
|
||||
- Workers: `internal/workers/*`
|
||||
- Cluster: `internal/service/cluster/*`
|
||||
- Headers: `pkg/service/http/header/*`
|
||||
|
||||
Useful Make Targets (selection)
|
||||
- `make help` — list targets
|
||||
- `make dep` — install Go/JS deps in container
|
||||
- `make build-go` — build backend
|
||||
- `make test-go` — backend tests (SQLite)
|
||||
- `make swag` — generate Swagger JSON in `internal/api/swagger.json`
|
||||
- `make fmt-go swag-fmt` — format Go code and Swagger annotations
|
||||
|
||||
See Also
|
||||
- AGENTS.md (repository rules and tips for agents)
|
||||
- Developer Guide (Setup/Tests/API) — links in AGENTS.md → Sources of Truth
|
||||
- Specs: `specs/dev/backend-testing.md`, `specs/portal/README.md`
|
10
Dockerfile
10
Dockerfile
@@ -1,8 +1,12 @@
|
||||
# Ubuntu 24.10 (Oracular Oriole)
|
||||
FROM photoprism/develop:250317-oracular
|
||||
# Ubuntu 25.04 (Plucky Puffin)
|
||||
FROM photoprism/develop:250912-plucky
|
||||
|
||||
# Harden npm usage by default (applies to npm ci / install in dev container)
|
||||
ENV NPM_CONFIG_IGNORE_SCRIPTS=true
|
||||
|
||||
## Alternative Environments:
|
||||
# FROM photoprism/develop:armv7 # ARMv7 (32bit)
|
||||
# FROM photoprism/develop:plucky # Ubuntu 25.04 (Plucky Puffin)
|
||||
# FROM photoprism/develop:oracular # Ubuntu 24.10 (Oracular Oriole)
|
||||
# FROM photoprism/develop:noble # Ubuntu 24.04 LTS (Noble Numbat)
|
||||
# FROM photoprism/develop:mantic # Ubuntu 23.10 (Mantic Minotaur)
|
||||
@@ -19,3 +23,5 @@ WORKDIR "/go/src/github.com/photoprism/photoprism"
|
||||
# Copy source to image.
|
||||
COPY . .
|
||||
COPY --chown=root:root /scripts/dist/ /scripts/
|
||||
|
||||
RUN sudo /scripts/install-yt-dlp.sh
|
||||
|
215
Makefile
215
Makefile
@@ -4,20 +4,23 @@
|
||||
# more about our team, products and services: https://www.photoprism.app/
|
||||
|
||||
export GO111MODULE=on
|
||||
export NPM_CONFIG_IGNORE_SCRIPTS ?= true
|
||||
|
||||
-include .semver
|
||||
-include .env
|
||||
export
|
||||
|
||||
# Binary file names.
|
||||
BINARY_NAME=photoprism
|
||||
GOIMPORTS=goimports
|
||||
|
||||
# Build version.
|
||||
SEMVER_MAJOR ?= 0
|
||||
# Build version string.
|
||||
SEMVER_MAJOR ?= 1
|
||||
export SEMVER_MAJOR
|
||||
SEMVER_MINOR ?= $(shell date -u +%y%m)
|
||||
export SEMVER_MINOR
|
||||
SEMVER_PATCH ?= $(shell date -u +%d)
|
||||
SEMVER_VERSION ?= $(SEMVER_MAJOR).$(SEMVER_MINOR).$(SEMVER_PATCH)
|
||||
export SEMVER_VERSION
|
||||
|
||||
# Build parameters.
|
||||
BUILD_PATH ?= $(shell realpath "./build")
|
||||
@@ -25,9 +28,12 @@ BUILD_DATE ?= $(shell date -u +%y%m%d)
|
||||
REPORT_DATE ?= $(shell date -u +%Y-%m-%d)
|
||||
BUILD_VERSION ?= $(shell git describe --always)
|
||||
BUILD_TAG ?= $(BUILD_DATE)-$(BUILD_VERSION)
|
||||
export BUILD_TAG
|
||||
BUILD_OS ?= $(shell uname -s)
|
||||
BUILD_ARCH ?= $(shell scripts/dist/arch.sh)
|
||||
BUILD_ARCH ?= $(shell ./scripts/dist/arch.sh)
|
||||
export BUILD_ARCH
|
||||
JS_BUILD_PATH ?= $(shell realpath "./assets/static/build")
|
||||
TF_VERSION ?= 2.18.0
|
||||
|
||||
# Install parameters.
|
||||
INSTALL_PATH ?= $(BUILD_PATH)/photoprism-ce_$(BUILD_TAG)-$(shell echo $(BUILD_OS) | tr '[:upper:]' '[:lower:]')-$(BUILD_ARCH)
|
||||
@@ -68,7 +74,9 @@ pull: docker-pull
|
||||
test: test-js test-go
|
||||
test-go: reset-sqlite run-test-go
|
||||
test-pkg: reset-sqlite run-test-pkg
|
||||
test-ai: reset-sqlite run-test-ai
|
||||
test-api: reset-sqlite run-test-api
|
||||
test-video: reset-sqlite run-test-video
|
||||
test-entity: reset-sqlite run-test-entity
|
||||
test-commands: reset-sqlite run-test-commands
|
||||
test-photoprism: reset-sqlite run-test-photoprism
|
||||
@@ -78,6 +86,9 @@ acceptance-run-chromium: storage/acceptance acceptance-auth-sqlite-restart wait
|
||||
acceptance-run-chromium-short: storage/acceptance acceptance-auth-sqlite-restart wait acceptance-auth-short acceptance-auth-sqlite-stop acceptance-sqlite-restart wait-2 acceptance-short acceptance-sqlite-stop
|
||||
acceptance-auth-run-chromium: storage/acceptance acceptance-auth-sqlite-restart wait acceptance-auth acceptance-auth-sqlite-stop
|
||||
acceptance-public-run-chromium: storage/acceptance acceptance-sqlite-restart wait acceptance acceptance-sqlite-stop
|
||||
help: list
|
||||
list:
|
||||
@awk '/^[[:alnum:]]+[^[:space:]]+:/ {printf "%s",substr($$1,1,length($$1)-1); if (match($$0,/#/)) {desc=substr($$0,RSTART+1); sub(/^[[:space:]]+/,"",desc); printf " - %s\n",desc} else printf "\n" }' "$(firstword $(MAKEFILE_LIST))"
|
||||
wait:
|
||||
sleep 20
|
||||
wait-2:
|
||||
@@ -94,8 +105,11 @@ devtools: install-go dep-npm
|
||||
.SILENT: help;
|
||||
logs:
|
||||
$(DOCKER_COMPOSE) logs -f
|
||||
help:
|
||||
@echo "For build instructions, visit <https://docs.photoprism.app/developer-guide/>."
|
||||
down:
|
||||
$(DOCKER_COMPOSE) --profile=all down --remove-orphans
|
||||
codex: dep-codex codex-version
|
||||
codex-version:
|
||||
codex --version
|
||||
docs: swag
|
||||
swag: swag-json
|
||||
swag-json:
|
||||
@@ -146,10 +160,12 @@ clean:
|
||||
[ ! -d "frontend/node_modules" ] || rm -rf frontend/node_modules
|
||||
[ ! -d "$(BUILD_PATH)" ] || rm -rf --preserve-root $(BUILD_PATH)
|
||||
[ ! -d "$(JS_BUILD_PATH)" ] || rm -rf --preserve-root $(JS_BUILD_PATH)
|
||||
clean-build:
|
||||
[ ! -d "$(BUILD_PATH)" ] || rm -rf --preserve-root $(BUILD_PATH)
|
||||
tar.gz:
|
||||
$(info Creating tar.gz archives from the directories in "$(BUILD_PATH)"...)
|
||||
find "$(BUILD_PATH)" -maxdepth 1 -mindepth 1 -type d -name "photoprism*" -exec tar --exclude='.[^/]*' -C {} -czf {}.tar.gz . \;
|
||||
pkg: pkg-amd64 pkg-arm64 pkg-armv7
|
||||
pkg: pkg-amd64 pkg-arm64
|
||||
pkg-amd64:
|
||||
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" photoprism/develop:jammy make all install tar.gz
|
||||
pkg-arm64:
|
||||
@@ -188,15 +204,15 @@ acceptance-sqlite-restart:
|
||||
rm -rf storage/acceptance/originals/2011
|
||||
rm -rf storage/acceptance/originals/2013
|
||||
rm -rf storage/acceptance/originals/2017
|
||||
./photoprism --auth-mode="public" -c "./storage/acceptance/config-sqlite" --test start -d
|
||||
./photoprism --auth-mode="public" -c "./storage/acceptance/config-sqlite" start -d
|
||||
acceptance-sqlite-stop:
|
||||
./photoprism --auth-mode="public" -c "./storage/acceptance/config-sqlite" --test stop
|
||||
./photoprism --auth-mode="public" -c "./storage/acceptance/config-sqlite" stop
|
||||
acceptance-auth-sqlite-restart:
|
||||
cp -f storage/acceptance/backup.db storage/acceptance/index.db
|
||||
cp -f storage/acceptance/config-sqlite/settingsBackup.yml storage/acceptance/config-sqlite/settings.yml
|
||||
./photoprism --auth-mode="password" -c "./storage/acceptance/config-sqlite" --test start -d
|
||||
./photoprism --auth-mode="password" -c "./storage/acceptance/config-sqlite" start -d
|
||||
acceptance-auth-sqlite-stop:
|
||||
./photoprism --auth-mode="password" -c "./storage/acceptance/config-sqlite" --test stop
|
||||
./photoprism --auth-mode="password" -c "./storage/acceptance/config-sqlite" stop
|
||||
start:
|
||||
./photoprism start -d
|
||||
stop:
|
||||
@@ -231,13 +247,24 @@ dep-list:
|
||||
dep-npm:
|
||||
sudo npm install -g npm
|
||||
dep-js:
|
||||
(cd frontend && npm ci --no-update-notifier --no-audit)
|
||||
(cd frontend && npm ci --ignore-scripts --no-update-notifier --no-audit)
|
||||
# TODO: If in the future we want to test in a real browser environment, add this (Playwright)
|
||||
# (cd frontend && npx playwright install chromium)
|
||||
dep-codex:
|
||||
@echo "Installing latest Codex CLI..."
|
||||
@[ -n "$(CODEX_HOME)" ] && [ "$(CODEX_HOME)" != "/" ] && install -d -m 700 -- "$(CODEX_HOME)" || true
|
||||
@if command -v sudo >/dev/null 2>&1; then \
|
||||
sudo npm install -g --location=global --no-fund --no-audit "@openai/codex@latest"; \
|
||||
else \
|
||||
npm install -g --location=global --no-fund --no-audit "@openai/codex@latest"; \
|
||||
fi
|
||||
dep-go:
|
||||
go build -v ./...
|
||||
dep-upgrade:
|
||||
go get -u -t ./...
|
||||
dep-upgrade-js:
|
||||
(cd frontend && npm update --legacy-peer-deps)
|
||||
frontend-update:
|
||||
make -C frontend update
|
||||
dep-upgrade-js: frontend-update
|
||||
dep-tensorflow:
|
||||
scripts/download-facenet.sh
|
||||
scripts/download-nasnet.sh
|
||||
@@ -271,41 +298,56 @@ build-static:
|
||||
scripts/build.sh static $(BINARY_NAME)
|
||||
build-libheif: build-libheif-amd64 build-libheif-arm64 build-libheif-armv7
|
||||
build-libheif-amd64:
|
||||
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/develop:oracular ./scripts/dist/build-libheif.sh v1.19.5
|
||||
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/develop:noble ./scripts/dist/build-libheif.sh v1.19.5
|
||||
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/develop:jammy ./scripts/dist/build-libheif.sh v1.19.5
|
||||
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/develop:bookworm ./scripts/dist/build-libheif.sh v1.19.5
|
||||
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/develop:plucky ./scripts/dist/build-libheif.sh v1.19.7
|
||||
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/develop:oracular ./scripts/dist/build-libheif.sh v1.19.7
|
||||
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/develop:noble ./scripts/dist/build-libheif.sh v1.19.7
|
||||
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/develop:jammy ./scripts/dist/build-libheif.sh v1.19.7
|
||||
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/develop:bookworm ./scripts/dist/build-libheif.sh v1.19.7
|
||||
build-libheif-arm64:
|
||||
docker run --rm -u $(UID) --platform=arm64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/develop:oracular ./scripts/dist/build-libheif.sh v1.19.5
|
||||
docker run --rm -u $(UID) --platform=arm64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/develop:noble ./scripts/dist/build-libheif.sh v1.19.5
|
||||
docker run --rm -u $(UID) --platform=arm64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/develop:jammy ./scripts/dist/build-libheif.sh v1.19.5
|
||||
docker run --rm -u $(UID) --platform=arm64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/develop:bookworm ./scripts/dist/build-libheif.sh v1.19.5
|
||||
docker run --rm -u $(UID) --platform=arm64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/develop:plucky ./scripts/dist/build-libheif.sh v1.19.7
|
||||
docker run --rm -u $(UID) --platform=arm64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/develop:oracular ./scripts/dist/build-libheif.sh v1.19.7
|
||||
docker run --rm -u $(UID) --platform=arm64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/develop:noble ./scripts/dist/build-libheif.sh v1.19.7
|
||||
docker run --rm -u $(UID) --platform=arm64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/develop:jammy ./scripts/dist/build-libheif.sh v1.19.7
|
||||
docker run --rm -u $(UID) --platform=arm64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/develop:bookworm ./scripts/dist/build-libheif.sh v1.19.7
|
||||
build-libheif-armv7:
|
||||
docker run --rm -u $(UID) --platform=arm --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm -e SYSTEM_ARCH=arm photoprism/develop:armv7 ./scripts/dist/build-libheif.sh v1.19.5
|
||||
docker run --rm -u $(UID) --platform=arm --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm -e SYSTEM_ARCH=arm photoprism/develop:jammy ./scripts/dist/build-libheif.sh v1.19.5
|
||||
docker run --rm -u $(UID) --platform=arm --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm -e SYSTEM_ARCH=arm photoprism/develop:armv7 ./scripts/dist/build-libheif.sh v1.19.7
|
||||
docker run --rm -u $(UID) --platform=arm --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm -e SYSTEM_ARCH=arm photoprism/develop:jammy ./scripts/dist/build-libheif.sh v1.19.7
|
||||
build-libheif-latest: build-libheif-amd64-latest build-libheif-arm64-latest build-libheif-armv7-latest
|
||||
build-libheif-amd64-latest:
|
||||
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/develop:plucky ./scripts/dist/build-libheif.sh
|
||||
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/develop:oracular ./scripts/dist/build-libheif.sh
|
||||
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/develop:noble ./scripts/dist/build-libheif.sh
|
||||
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/develop:jammy ./scripts/dist/build-libheif.sh
|
||||
build-libheif-arm64-latest:
|
||||
docker run --rm -u $(UID) --platform=arm64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/develop:plucky ./scripts/dist/build-libheif.sh
|
||||
docker run --rm -u $(UID) --platform=arm64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/develop:oracular ./scripts/dist/build-libheif.sh
|
||||
docker run --rm -u $(UID) --platform=arm64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/develop:noble ./scripts/dist/build-libheif.sh
|
||||
docker run --rm -u $(UID) --platform=arm64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/develop:jammy ./scripts/dist/build-libheif.sh
|
||||
build-libheif-armv7-latest:
|
||||
docker run --rm -u $(UID) --platform=arm --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm -e SYSTEM_ARCH=arm photoprism/develop:armv7 ./scripts/dist/build-libheif.sh
|
||||
docker run --rm -u $(UID) --platform=arm --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm -e SYSTEM_ARCH=arm photoprism/develop:jammy ./scripts/dist/build-libheif.sh
|
||||
build-tensorflow:
|
||||
docker build -t photoprism/tensorflow:build docker/tensorflow
|
||||
docker run -ti photoprism/tensorflow:build bash
|
||||
build-tensorflow-arm64:
|
||||
docker build -t photoprism/tensorflow:arm64 docker/tensorflow/arm64
|
||||
docker run -ti photoprism/tensorflow:arm64 bash
|
||||
build-tensorflow: docker-tensorflow-amd64
|
||||
docker-tensorflow: docker-tensorflow-amd64
|
||||
docker-tensorflow-amd64:
|
||||
docker build --pull --no-cache -t photoprism/tensorflow:latest -t photoprism/tensorflow:amd64 -t photoprism/tensorflow:$(TF_VERSION)-amd64 --build-arg TF_VERSION=$(TF_VERSION) docker/tensorflow
|
||||
terminal-tensorflow: terminal-tensorflow-amd64
|
||||
terminal-tensorflow-amd64:
|
||||
mkdir -p ./build
|
||||
docker run --rm --pull missing -ti --platform=amd64 -v "./build:/build" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/tensorflow:amd64 bash
|
||||
build-tensorflow-arm64: docker-tensorflow-arm64
|
||||
docker-tensorflow-arm64:
|
||||
docker build --pull --no-cache -t photoprism/tensorflow:arm64 -t photoprism/tensorflow:$(TF_VERSION)-arm64 --build-arg TF_VERSION=$(TF_VERSION) docker/tensorflow/arm64
|
||||
terminal-tensorflow-arm64:
|
||||
mkdir -p ./build
|
||||
docker run --rm --pull missing -ti --platform=arm64 -v "./build:/build" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/tensorflow:arm64 bash
|
||||
build-setup: build-setup-nas-raspberry-pi
|
||||
build-setup-nas-raspberry-pi:
|
||||
./scripts/setup/nas/raspberry-pi/build.sh
|
||||
watch-js:
|
||||
(cd frontend && env BUILD_ENV=development NODE_ENV=production npm run watch)
|
||||
test-js:
|
||||
$(info Running JS unit tests...)
|
||||
(cd frontend && env TZ=UTC BUILD_ENV=development NODE_ENV=development BABEL_ENV=test npm run test)
|
||||
(cd frontend && npm run test)
|
||||
acceptance:
|
||||
$(info Running public-mode tests in Chrome...)
|
||||
(cd frontend && npm run testcafe -- "chrome --headless=new" --test-grep "^(Multi-Window)\:*" --test-meta mode=public --config-file ./testcaferc.json --experimental-multiple-windows "tests/acceptance" && npm run testcafe -- "chrome --headless=new" --test-grep "^(Common|Core)\:*" --test-meta mode=public --config-file ./testcaferc.json "tests/acceptance")
|
||||
@@ -324,6 +366,15 @@ acceptance-auth-short:
|
||||
acceptance-auth-firefox:
|
||||
$(info Running JS acceptance-auth tests in Firefox...)
|
||||
(cd frontend && npm run testcafe -- firefox:headless --test-grep "^(Common|Core)\:*" --test-meta mode=auth --config-file ./testcaferc.json --disable-native-automation "tests/acceptance")
|
||||
vitest-watch:
|
||||
$(info Running Vitest unit tests in watch mode...)
|
||||
(cd frontend && npm run test-watch)
|
||||
vitest-coverage:
|
||||
$(info Running Vitest unit tests with coverage...)
|
||||
(cd frontend && npm run test-coverage)
|
||||
vitest-component:
|
||||
$(info Running Vitest component tests...)
|
||||
(cd frontend && npm run test-component)
|
||||
reset-mariadb:
|
||||
$(info Resetting photoprism database...)
|
||||
mysql < scripts/sql/reset-photoprism.sql
|
||||
@@ -354,9 +405,15 @@ run-test-mariadb:
|
||||
run-test-pkg:
|
||||
$(info Running all Go tests in "/pkg"...)
|
||||
$(GOTEST) -parallel 2 -count 1 -cpu 2 -tags="slow,develop" -timeout 20m ./pkg/...
|
||||
run-test-ai:
|
||||
$(info Running all AI tests...)
|
||||
$(GOTEST) -parallel 2 -count 1 -cpu 2 -tags="slow,develop" -timeout 20m ./internal/ai/...
|
||||
run-test-api:
|
||||
$(info Running all API tests...)
|
||||
$(GOTEST) -parallel 2 -count 1 -cpu 2 -tags="slow,develop" -timeout 20m ./internal/api/...
|
||||
run-test-video:
|
||||
$(info Running all video tests...)
|
||||
$(GOTEST) -parallel 2 -count 1 -cpu 2 -tags="slow,develop" -timeout 20m ./internal/ffmpeg/... ./internal/photoprism/dl/... ./pkg/media/...
|
||||
run-test-entity:
|
||||
$(info Running all Entity tests...)
|
||||
$(GOTEST) -parallel 2 -count 1 -cpu 2 -tags="slow,develop" -timeout 20m ./internal/entity/...
|
||||
@@ -380,31 +437,57 @@ test-coverage:
|
||||
go test -parallel 1 -count 1 -cpu 1 -failfast -tags="slow,develop" -timeout 30m -coverprofile coverage.txt -covermode atomic ./pkg/... ./internal/...
|
||||
go tool cover -html=coverage.txt -o coverage.html
|
||||
go tool cover -func coverage.txt | grep total:
|
||||
git-pull:
|
||||
@echo "Pulling changes from remote repositories..."; \
|
||||
if [ -d .git ]; then \
|
||||
echo "Updating photoprism"; \
|
||||
git pull --ff-only || echo "Warning: git pull failed in root"; \
|
||||
else \
|
||||
echo "Skipping: current directory is not a Git repo"; \
|
||||
fi; \
|
||||
for d in */ ; do \
|
||||
[ -d "$$d" ] || continue; \
|
||||
[ -d "$$d/.git" ] || continue; \
|
||||
echo "Updating photoprism/$$d"; \
|
||||
git -C "$$d" pull --ff-only || echo "Warning: git pull failed in $$d"; \
|
||||
done;
|
||||
docker-pull:
|
||||
$(DOCKER_COMPOSE) --profile=all pull --ignore-pull-failures
|
||||
$(DOCKER_COMPOSE) -f compose.latest.yaml pull --ignore-pull-failures
|
||||
docker-build:
|
||||
$(DOCKER_COMPOSE) --profile=all pull --ignore-pull-failures
|
||||
$(DOCKER_COMPOSE) down --remove-orphans
|
||||
$(DOCKER_COMPOSE) build --pull
|
||||
docker-nvidia: docker-nvidia-up
|
||||
docker-nvidia-up:
|
||||
docker compose -f compose.nvidia.yaml up
|
||||
docker-local-up:
|
||||
$(DOCKER_COMPOSE) -f compose.local.yaml up --force-recreate
|
||||
docker-local-down:
|
||||
$(DOCKER_COMPOSE) -f compose.local.yaml down -V
|
||||
nvidia: nvidia-up
|
||||
nvidia-build:
|
||||
$(DOCKER_COMPOSE) --profile=qdrant -f compose.nvidia.yaml pull --ignore-pull-failures
|
||||
$(DOCKER_COMPOSE) --profile=qdrant -f compose.nvidia.yaml build
|
||||
nvidia-up:
|
||||
$(DOCKER_COMPOSE) --profile=qdrant -f compose.nvidia.yaml pull --ignore-pull-failures
|
||||
$(DOCKER_COMPOSE) --profile=qdrant -f compose.nvidia.yaml up --remove-orphans
|
||||
nvidia-down:
|
||||
$(DOCKER_COMPOSE) --profile=qdrant -f compose.nvidia.yaml down --remove-orphans
|
||||
intel: intel-up
|
||||
intel-build:
|
||||
$(DOCKER_COMPOSE) -f compose.intel.yaml pull --ignore-pull-failures
|
||||
$(DOCKER_COMPOSE) -f compose.intel.yaml build
|
||||
intel-up:
|
||||
$(DOCKER_COMPOSE) -f compose.intel.yaml pull --ignore-pull-failures
|
||||
$(DOCKER_COMPOSE) -f compose.intel.yaml up --remove-orphans
|
||||
intel-down:
|
||||
$(DOCKER_COMPOSE) -f compose.intel.yaml down --remove-orphans
|
||||
develop: docker-develop
|
||||
docker-develop: docker-develop-latest
|
||||
docker-develop-all: docker-develop-latest docker-develop-other
|
||||
docker-develop-latest: docker-develop-ubuntu
|
||||
docker-develop-debian: docker-develop-bookworm docker-develop-bookworm-slim
|
||||
docker-develop-ubuntu: docker-develop-oracular docker-develop-oracular-slim
|
||||
docker-develop-ubuntu: docker-develop-plucky docker-develop-plucky-slim
|
||||
docker-develop-other: docker-develop-debian docker-develop-bullseye docker-develop-bullseye-slim docker-develop-buster
|
||||
docker-develop-bookworm:
|
||||
docker pull --platform=amd64 debian:bookworm-slim
|
||||
docker pull --platform=arm64 debian:bookworm-slim
|
||||
docker pull --platform=arm debian:bookworm-slim
|
||||
scripts/docker/buildx-multi.sh develop linux/amd64,linux/arm64,linux/arm bookworm /bookworm "-t photoprism/develop:debian"
|
||||
scripts/docker/buildx-multi.sh develop linux/amd64,linux/arm64 bookworm /bookworm "-t photoprism/develop:debian"
|
||||
docker-develop-bookworm-slim:
|
||||
docker pull --platform=amd64 debian:bookworm-slim
|
||||
docker pull --platform=arm64 debian:bookworm-slim
|
||||
@@ -413,7 +496,7 @@ docker-develop-bullseye:
|
||||
docker pull --platform=amd64 golang:1-bullseye
|
||||
docker pull --platform=arm64 golang:1-bullseye
|
||||
docker pull --platform=arm golang:1-bullseye
|
||||
scripts/docker/buildx-multi.sh develop linux/amd64,linux/arm64,linux/arm bullseye /bullseye
|
||||
scripts/docker/buildx-multi.sh develop linux/amd64,linux/arm64 bullseye /bullseye
|
||||
docker-develop-bullseye-slim:
|
||||
docker pull --platform=amd64 debian:bullseye-slim
|
||||
docker pull --platform=arm64 debian:bullseye-slim
|
||||
@@ -433,8 +516,7 @@ docker-develop-impish:
|
||||
docker-develop-jammy:
|
||||
docker pull --platform=amd64 ubuntu:jammy
|
||||
docker pull --platform=arm64 ubuntu:jammy
|
||||
docker pull --platform=arm ubuntu:jammy
|
||||
scripts/docker/buildx-multi.sh develop linux/amd64,linux/arm64,linux/arm jammy /jammy
|
||||
scripts/docker/buildx-multi.sh develop linux/amd64,linux/arm64 jammy /jammy
|
||||
docker-develop-jammy-slim:
|
||||
docker pull --platform=amd64 ubuntu:jammy
|
||||
docker pull --platform=arm64 ubuntu:jammy
|
||||
@@ -466,11 +548,19 @@ docker-develop-noble-slim:
|
||||
docker-develop-oracular:
|
||||
docker pull --platform=amd64 ubuntu:oracular
|
||||
docker pull --platform=arm64 ubuntu:oracular
|
||||
scripts/docker/buildx-multi.sh develop linux/amd64,linux/arm64 oracular /oracular "-t photoprism/develop:latest -t photoprism/develop:ubuntu"
|
||||
scripts/docker/buildx-multi.sh develop linux/amd64,linux/arm64 oracular /oracular
|
||||
docker-develop-oracular-slim:
|
||||
docker pull --platform=amd64 ubuntu:oracular
|
||||
docker pull --platform=arm64 ubuntu:oracular
|
||||
scripts/docker/buildx-multi.sh develop linux/amd64,linux/arm64 oracular-slim /oracular-slim
|
||||
docker-develop-plucky:
|
||||
docker pull --platform=amd64 ubuntu:plucky
|
||||
docker pull --platform=arm64 ubuntu:plucky
|
||||
scripts/docker/buildx-multi.sh develop linux/amd64,linux/arm64 plucky /plucky "-t photoprism/develop:latest -t photoprism/develop:ubuntu"
|
||||
docker-develop-plucky-slim:
|
||||
docker pull --platform=amd64 ubuntu:plucky
|
||||
docker pull --platform=arm64 ubuntu:plucky
|
||||
scripts/docker/buildx-multi.sh develop linux/amd64,linux/arm64 plucky-slim /plucky-slim
|
||||
unstable: docker-unstable
|
||||
docker-unstable: docker-unstable-mantic
|
||||
docker-unstable-jammy:
|
||||
@@ -488,10 +578,10 @@ docker-unstable-mantic:
|
||||
preview: docker-preview-ce
|
||||
docker-preview: docker-preview-ce
|
||||
docker-preview-all: docker-preview-latest docker-preview-other
|
||||
docker-preview-ce: docker-preview-oracular
|
||||
docker-preview-ce: docker-preview-plucky
|
||||
docker-preview-latest: docker-preview-ubuntu
|
||||
docker-preview-debian: docker-preview-bookworm
|
||||
docker-preview-ubuntu: docker-preview-oracular
|
||||
docker-preview-ubuntu: docker-preview-plucky
|
||||
docker-preview-other: docker-preview-debian docker-preview-bullseye
|
||||
docker-preview-arm: docker-preview-arm64 docker-preview-armv7
|
||||
docker-preview-bookworm:
|
||||
@@ -556,12 +646,18 @@ docker-preview-oracular:
|
||||
docker pull --platform=arm64 photoprism/develop:oracular
|
||||
docker pull --platform=arm64 photoprism/develop:oracular-slim
|
||||
scripts/docker/buildx-multi.sh photoprism linux/amd64,linux/arm64 preview-ce /oracular
|
||||
docker-preview-plucky:
|
||||
docker pull --platform=amd64 photoprism/develop:plucky
|
||||
docker pull --platform=amd64 photoprism/develop:plucky-slim
|
||||
docker pull --platform=arm64 photoprism/develop:plucky
|
||||
docker pull --platform=arm64 photoprism/develop:plucky-slim
|
||||
scripts/docker/buildx-multi.sh photoprism linux/amd64,linux/arm64 preview-ce /plucky
|
||||
release: docker-release
|
||||
docker-release: docker-release-latest
|
||||
docker-release-all: docker-release-latest docker-release-other
|
||||
docker-release-latest: docker-release-ubuntu
|
||||
docker-release-debian: docker-release-bookworm
|
||||
docker-release-ubuntu: docker-release-oracular
|
||||
docker-release-ubuntu: docker-release-plucky
|
||||
docker-release-other: docker-release-debian docker-release-bullseye
|
||||
docker-release-arm: docker-release-arm64 docker-release-armv7
|
||||
docker-release-bookworm:
|
||||
@@ -626,6 +722,16 @@ docker-release-oracular:
|
||||
docker pull --platform=arm64 photoprism/develop:oracular
|
||||
docker pull --platform=arm64 photoprism/develop:oracular-slim
|
||||
scripts/docker/buildx-multi.sh photoprism linux/amd64,linux/arm64 ce /oracular
|
||||
docker-release-plucky:
|
||||
docker pull --platform=amd64 photoprism/develop:plucky
|
||||
docker pull --platform=amd64 photoprism/develop:plucky-slim
|
||||
docker pull --platform=arm64 photoprism/develop:plucky
|
||||
docker pull --platform=arm64 photoprism/develop:plucky-slim
|
||||
scripts/docker/buildx-multi.sh photoprism linux/amd64,linux/arm64 ce /plucky
|
||||
start-traefik:
|
||||
$(DOCKER_COMPOSE) up -d --wait traefik
|
||||
stop-traefik:
|
||||
$(DOCKER_COMPOSE) down traefik
|
||||
start-local:
|
||||
$(DOCKER_COMPOSE) -f compose.local.yaml up -d --wait
|
||||
stop-local:
|
||||
@@ -668,8 +774,12 @@ terminal-preview:
|
||||
$(DOCKER_COMPOSE) -f compose.preview.yaml exec photoprism-preview bash
|
||||
logs-preview:
|
||||
$(DOCKER_COMPOSE) -f compose.preview.yaml logs -f photoprism-preview
|
||||
docker-local: docker-local-oracular
|
||||
docker-local-all: docker-local-oracular docker-local-noble docker-local-mantic docker-local-lunar docker-local-jammy docker-local-bookworm docker-local-bullseye docker-local-buster
|
||||
docker-local: docker-local-plucky
|
||||
docker-local-up:
|
||||
$(DOCKER_COMPOSE) -f compose.local.yaml up --force-recreate
|
||||
docker-local-down:
|
||||
$(DOCKER_COMPOSE) -f compose.local.yaml down --remove-orphans
|
||||
docker-local-all: docker-local-plucky docker-local-oracular docker-local-noble docker-local-mantic docker-local-lunar docker-local-jammy docker-local-bookworm docker-local-bullseye docker-local-buster
|
||||
docker-local-bookworm:
|
||||
docker pull photoprism/develop:bookworm
|
||||
docker pull photoprism/develop:bookworm-slim
|
||||
@@ -706,6 +816,10 @@ docker-local-oracular:
|
||||
docker pull photoprism/develop:oracular
|
||||
docker pull ubuntu:oracular
|
||||
scripts/docker/build.sh photoprism ce-oracular /oracular "-t photoprism/photoprism:local"
|
||||
docker-local-plucky:
|
||||
docker pull photoprism/develop:plucky
|
||||
docker pull ubuntu:plucky
|
||||
scripts/docker/build.sh photoprism ce-plucky /plucky "-t photoprism/photoprism:local"
|
||||
local-develop: docker-local-develop
|
||||
docker-local-develop: docker-local-develop-oracular
|
||||
docker-local-develop-all: docker-local-develop-oracular docker-local-develop-noble docker-local-develop-mantic docker-local-develop-lunar docker-local-develop-jammy docker-local-develop-bookworm docker-local-develop-bullseye docker-local-develop-buster docker-local-develop-impish
|
||||
@@ -736,6 +850,9 @@ docker-local-develop-noble:
|
||||
docker-local-develop-oracular:
|
||||
docker pull ubuntu:oracular
|
||||
scripts/docker/build.sh develop oracular /oracular
|
||||
docker-local-develop-plucky:
|
||||
docker pull ubuntu:plucky
|
||||
scripts/docker/build.sh develop plucky /plucky
|
||||
docker-ddns:
|
||||
docker pull golang:alpine
|
||||
scripts/docker/buildx-multi.sh ddns linux/amd64,linux/arm64 $(BUILD_DATE)
|
||||
|
34
README.md
34
README.md
@@ -12,7 +12,7 @@ PhotoPrism® is an AI-Powered Photos App for the [Decentralized Web](https://en.
|
||||
It makes use of the latest technologies to tag and find pictures automatically without getting in your way.
|
||||
You can run it at home, on a private server, or in the cloud.
|
||||
|
||||

|
||||

|
||||
|
||||
To get a first impression, you are welcome to play with our [public demo](https://try.photoprism.app/). Please be careful not to upload any private, unlawful or offensive pictures.
|
||||
|
||||
@@ -20,23 +20,21 @@ To get a first impression, you are welcome to play with our [public demo](https:
|
||||
|
||||
**Our mission is to provide the most user- and privacy-friendly solution to keep your pictures organized and accessible.** That's why PhotoPrism was built from the ground up to run wherever you need it, without compromising freedom, privacy, or functionality:
|
||||
|
||||
* Browse [all your photos](https://docs.photoprism.app/user-guide/organize/browse/) and [videos](https://try.photoprism.app/library/videos) without worrying about [RAW conversion, duplicates or video formats](https://docs.photoprism.app/user-guide/settings/library/)
|
||||
* Easily find specific pictures using [powerful search filters](https://try.photoprism.app/library/browse?view=cards&q=flower%20color%3Ared)
|
||||
* Recognizes [the faces of your family and friends](https://try.photoprism.app/library/people)
|
||||
* [Automatic classification](https://try.photoprism.app/library/labels) of pictures based on their content and location
|
||||
* [Play Live Photos](https://try.photoprism.app/library/live) by hovering over them in [albums](https://try.photoprism.app/library/albums) and [search results](https://try.photoprism.app/library/browse?view=cards&q=type%3Alive)
|
||||
* Since the [User Interface](https://try.photoprism.app/) is a [Progressive Web App](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps),
|
||||
it provides a native app-like experience, and you can conveniently install it on the home screen of all major operating systems and mobile devices
|
||||
* Includes four high-resolution [World Maps](https://try.photoprism.app/library/places) to bring back the memories of your favorite trips
|
||||
* Metadata is extracted and merged from Exif, XMP, and other sources such as Google Photos
|
||||
* Many more image properties like [Colors](https://try.photoprism.app/library/browse?view=cards&q=color:red), [Chroma](https://try.photoprism.app/library/browse?view=cards&q=mono%3Atrue), and [Quality](https://try.photoprism.app/library/review) can be searched as well
|
||||
* Use [PhotoSync](https://link.photoprism.app/photosync) to securely backup iOS and Android phones in the background
|
||||
* WebDAV clients such as Microsoft's Windows Explorer and Apple's Finder [can connect directly](https://docs.photoprism.app/user-guide/sync/webdav/) to PhotoPrism, allowing you to open, edit, and delete files from your computer as if they were local
|
||||
<img align="right" height="270" src="https://dl.photoprism.app/img/ui/2025/iphone-crocus-540px.png">
|
||||
|
||||
* Browse [all your pictures](https://docs.photoprism.app/user-guide/organize/browse/) without worrying about [RAW images](https://www.photoprism.app/kb/file-formats) or [video formats](https://docs.photoprism.app/user-guide/organize/video/)
|
||||
* Whether you're using a phone, tablet, or desktop computer, our [intuitive PWA](https://try.photoprism.app/) provides a native app-like experience and can be [easily installed](https://docs.photoprism.app/user-guide/pwa/) on your home screen
|
||||
* Quickly find specific photos and videos with [powerful search filters](https://docs.photoprism.app/user-guide/search/filters/) that can be combined and are available for [many different properties](https://docs.photoprism.app/user-guide/search/filters/#filter-reference), including [labels](https://try.photoprism.app/library/labels), [location](https://try.photoprism.app/library/places?q=s2:47a85a63f764), [resolution](https://try.photoprism.app/library/browse?view=cards&q=mp:4), [color](https://try.photoprism.app/library/browse?view=cards&q=color:red), [chroma](https://try.photoprism.app/library/browse?view=cards&q=mono%3Atrue), and [quality](https://try.photoprism.app/library/review)
|
||||
* [Automatically labels your pictures](https://try.photoprism.app/library/labels) based on content and location, and recognizes the faces of [your family and friends](https://try.photoprism.app/library/people/new)
|
||||
* [Live Photos](https://try.photoprism.app/library/live) start playing when you [hover over them](https://try.photoprism.app/library/browse?view=cards&q=type%3Alive) and when viewing a slideshow
|
||||
* Six high-resolution [World Maps](https://try.photoprism.app/library/places) and our [privacy-preserving geocoding service](https://docs.photoprism.app/getting-started/#maps-places) help bring back memories of your favorite trips and let you explore the world
|
||||
* Metadata can be extracted and merged from Exif, XMP, and other sources like Google Photos
|
||||
* [Use compatible apps](https://docs.photoprism.app/user-guide/native-apps/) like [PhotoSync](https://link.photoprism.app/photosync) to back up iOS and Android phones in the background
|
||||
* WebDAV clients such as [Microsoft's Windows Explorer](https://docs.photoprism.app/user-guide/sync/webdav/#__tabbed_1_2) and [Apple's Finder](https://docs.photoprism.app/user-guide/sync/webdav/#connect-to-a-webdav-server) can [connect directly to PhotoPrism](https://docs.photoprism.app/user-guide/sync/webdav/), allowing you to open, edit, and delete files from your computer as if they were local
|
||||
|
||||
Being completely [**self-funded and independent**](https://link.photoprism.app/membership), we can promise you that we will [never sell your data](https://www.photoprism.app/privacy) and that we will [always be transparent](https://www.photoprism.app/terms) about our software and services. Your data will never be shared with Google, Amazon, Microsoft or Apple unless you intentionally upload files to one of their services. 🔒
|
||||
|
||||
## Getting Started ##
|
||||
<img align="right" width="25%" src="https://www.photoprism.app/user/pages/01.home/03._screenshots/iphone-maps-hybrid-540px.png">
|
||||
|
||||
Step-by-step [installation instructions](https://docs.photoprism.app/getting-started/) for our self-hosted [community edition](https://link.photoprism.app/personal-editions) can be found on [docs.photoprism.app](https://docs.photoprism.app/getting-started/) - all you need is a Web browser and [Docker](https://docs.docker.com/get-docker/) to run the server. It is available for Mac, Linux, and Windows.
|
||||
|
||||
@@ -79,11 +77,15 @@ Common problems can be quickly diagnosed and solved using our [Troubleshooting C
|
||||
|
||||
## Upcoming Features and Enhancements ##
|
||||
|
||||
<a href="https://github.com/orgs/photoprism/projects/5"><img align="right" height="240" src="https://dl.photoprism.app/img/ui/2025/upcoming-features-240px.png"></a>
|
||||
|
||||
Our [Project Roadmap](https://link.photoprism.app/roadmap) shows what tasks are in progress and what features will be implemented next. You are invited to give ideas you like a thumbs-up, so we know what's most popular.
|
||||
|
||||
Be aware that we have a zero-bug policy and do our best to help users when they need support or have other questions. This comes at a price though, as we can't give exact release dates for new features. Our team receives many more requests than can be implemented, so we want to emphasize that we are in no way obligated to implement the features, enhancements, or other changes you request. We do, however, appreciate your feedback and carefully consider all requests.
|
||||
|
||||
**Because sustained funding is key to quickly releasing new features, we encourage you to support our mission by [signing up as a sponsor](https://link.photoprism.app/sponsor) or purchasing a [commercial license](https://www.photoprism.app/teams). Ultimately, that's what's best for the product and the community.**
|
||||
**Because sustained funding is key to quickly releasing new features, we encourage you to support our mission by [signing up for a personal membership](https://link.photoprism.app/membership) or [purchasing a commercial license](https://www.photoprism.app/teams#compare).**
|
||||
|
||||
[Become a Member ›](https://link.photoprism.app/membership)
|
||||
|
||||
## GitHub Issues ⚠️ ##
|
||||
|
||||
@@ -96,6 +98,8 @@ We kindly ask you not to report bugs via GitHub Issues **unless you are certain
|
||||
|
||||
## Connect with the Community ##
|
||||
|
||||
<a href="https://link.photoprism.app/chat"><img align="right" width="144" height="144" src="https://dl.photoprism.app/img/brands/element-logo.svg"></a>
|
||||
|
||||
Follow us on [Mastodon](https://floss.social/@photoprism), [Bluesky](https://bsky.app/profile/photoprism.app), or join the [Community Chat](https://link.photoprism.app/chat) to get regular updates, connect with other users, and discuss your ideas. Our [Code of Conduct](https://www.photoprism.app/code-of-conduct) explains the "dos and don’ts" when interacting with other community members.
|
||||
|
||||
As a [contributor](CONTRIBUTING.md), you are also welcome to [contact us directly](https://www.photoprism.app/contact) if you have something on your mind that you don't want to discuss publicly. Please note, however, that due to the high volume of emails we receive, our team may be unable to get back to you immediately. We do our best to respond within five business days or less.
|
||||
|
@@ -30,6 +30,8 @@ You are [welcome to contact us](https://www.photoprism.app/contact) for change r
|
||||
|
||||
**[Andreas Krizek](https://github.com/Cosmic314)** (January 2025)
|
||||
|
||||
**[Jason Grim](https://github.com/jgrim)** (June 2025)
|
||||
|
||||
## Gold Sponsors ##
|
||||
|
||||
[**Simen Eriksen**](https://github.com/dennorske) (GitHub Sponsors, December 2019)
|
||||
|
@@ -1,4 +1,5 @@
|
||||
examples
|
||||
README.md
|
||||
docs
|
||||
.*
|
||||
.*
|
||||
_*
|
BIN
assets/examples/bear.m2ts
Normal file
BIN
assets/examples/bear.m2ts
Normal file
Binary file not shown.
BIN
assets/examples/cat_224.jpeg
Normal file
BIN
assets/examples/cat_224.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
BIN
assets/examples/cat_720.jpeg
Normal file
BIN
assets/examples/cat_720.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 98 KiB |
BIN
assets/examples/example.zip
Normal file
BIN
assets/examples/example.zip
Normal file
Binary file not shown.
BIN
assets/examples/green.jpg
Normal file
BIN
assets/examples/green.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
BIN
assets/examples/m2ts.mp4
Normal file
BIN
assets/examples/m2ts.mp4
Normal file
Binary file not shown.
@@ -2,10 +2,9 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-03-11 19:22+0000\n"
|
||||
"PO-Revision-Date: 2025-03-11 19:36+0000\n"
|
||||
"Last-Translator: Google Cloud Translation Basic <noreply-mt-google-"
|
||||
"translate@weblate.org>\n"
|
||||
"POT-Creation-Date: 2025-03-15 12:54+0000\n"
|
||||
"PO-Revision-Date: 2025-07-21 11:32+0000\n"
|
||||
"Last-Translator: NoufAM <Nouf.almashghouni@deg.shj.ae>\n"
|
||||
"Language-Team: none\n"
|
||||
"Language: ar\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@@ -13,11 +12,11 @@ msgstr ""
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
|
||||
"&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n"
|
||||
"X-Generator: Weblate 5.9.2\n"
|
||||
"X-Generator: Weblate 5.12.2\n"
|
||||
|
||||
#: messages.go:103
|
||||
msgid "Something went wrong, try again"
|
||||
msgstr "حدث خطأ ما حاول مرة أخرى"
|
||||
msgstr "حدث خطأ ما، حاول مرة أخرى"
|
||||
|
||||
#: messages.go:104
|
||||
msgid "Unable to do that"
|
||||
@@ -38,7 +37,7 @@ msgstr "%s موجود بالفعل"
|
||||
|
||||
#: messages.go:108
|
||||
msgid "Not found"
|
||||
msgstr "لم يتم العثور على"
|
||||
msgstr "لم يتم العثور"
|
||||
|
||||
#: messages.go:109
|
||||
msgid "File not found"
|
||||
@@ -118,23 +117,23 @@ msgstr "طلب الاذن مرفوض"
|
||||
|
||||
#: messages.go:128
|
||||
msgid "Upload might be offensive"
|
||||
msgstr "تحميل قد يكون مسيئا"
|
||||
msgstr "المحتوى المرفوع قد يكون مسيئا"
|
||||
|
||||
#: messages.go:129
|
||||
msgid "Upload failed"
|
||||
msgstr "التحميل فشل"
|
||||
msgstr "فشل التحميل"
|
||||
|
||||
#: messages.go:130
|
||||
msgid "No items selected"
|
||||
msgstr "لم يتم تحديد الاختيار"
|
||||
msgstr "لم يتم اختيار المحتوى"
|
||||
|
||||
#: messages.go:131
|
||||
msgid "Failed creating file, please check permissions"
|
||||
msgstr "فشل إنشاء الملف ، يرجى التحقق من الأذونات"
|
||||
msgstr "فشل إنشاء الملف ، يرجى التحقق من الصلاحيات"
|
||||
|
||||
#: messages.go:132
|
||||
msgid "Failed creating folder, please check permissions"
|
||||
msgstr "فشل إنشاء المجلد ، يرجى التحقق من الأذونات"
|
||||
msgstr "لم يتم إنشاء المجلد ، يرجى التحقق من الصلاحيات"
|
||||
|
||||
#: messages.go:133
|
||||
msgid "Could not connect, please try again"
|
||||
@@ -150,15 +149,15 @@ msgstr "رمز التحقق غير صالح، يرجى المحاولة مرة
|
||||
|
||||
#: messages.go:136
|
||||
msgid "Invalid password, please try again"
|
||||
msgstr "كلمة السر غير مطابقة، برجاء حاول مرة أخرى"
|
||||
msgstr "كلمة السر غير مطابقة، يرجى المحاولة مرة أخرى"
|
||||
|
||||
#: messages.go:137
|
||||
msgid "Feature disabled"
|
||||
msgstr "الخاصية معطلة"
|
||||
msgstr "الخاصية غير مفعلة"
|
||||
|
||||
#: messages.go:138
|
||||
msgid "No labels selected"
|
||||
msgstr "لم يتم تحديد تسميات"
|
||||
msgstr "لم يتم تحديد المعرفات"
|
||||
|
||||
#: messages.go:139
|
||||
msgid "No albums selected"
|
||||
@@ -170,7 +169,7 @@ msgstr "لا توجد ملفات متاحة للتنزيل"
|
||||
|
||||
#: messages.go:141
|
||||
msgid "Failed to create zip file"
|
||||
msgstr "فشل إنشاء ملف مضغوط"
|
||||
msgstr "فشل في إنشاء ملف مضغوط"
|
||||
|
||||
#: messages.go:142
|
||||
msgid "Invalid credentials"
|
||||
@@ -178,7 +177,7 @@ msgstr "بيانات الاعتماد غير صالحة"
|
||||
|
||||
#: messages.go:143
|
||||
msgid "Invalid link"
|
||||
msgstr "ارتباط غير صالح"
|
||||
msgstr "رابط غير صالح"
|
||||
|
||||
#: messages.go:144
|
||||
msgid "Invalid name"
|
||||
@@ -186,7 +185,7 @@ msgstr "اسم غير صحيح"
|
||||
|
||||
#: messages.go:145
|
||||
msgid "Busy, please try again later"
|
||||
msgstr "مشغول ، يرجى المحاولة مرة أخرى في وقت لاحق"
|
||||
msgstr "مشغول، يرجى المحاولة مرة أخرى في وقت لاحق"
|
||||
|
||||
#: messages.go:146
|
||||
#, c-format
|
||||
@@ -207,7 +206,7 @@ msgstr "مساحة تخزين غير كافية"
|
||||
|
||||
#: messages.go:150
|
||||
msgid "Quota exceeded"
|
||||
msgstr "تم تجاوز الحصة"
|
||||
msgstr "تم تجاوز المساحة المخصصة"
|
||||
|
||||
#: messages.go:153
|
||||
msgid "Changes successfully saved"
|
||||
@@ -376,7 +375,7 @@ msgstr "تمت أرشفة الاختيار"
|
||||
|
||||
#: messages.go:191
|
||||
msgid "Selection restored"
|
||||
msgstr "تمت استعادة التحديد"
|
||||
msgstr "تم استعادة المحتوى المحدد"
|
||||
|
||||
#: messages.go:192
|
||||
msgid "Selection marked as private"
|
||||
@@ -389,7 +388,7 @@ msgstr "تم حذف الألبومات"
|
||||
#: messages.go:194
|
||||
#, c-format
|
||||
msgid "Zip created in %d s"
|
||||
msgstr "إنشاء الملف المضغوط خلال %d ثوانٍ"
|
||||
msgstr "تم إنشاء الملف المضغوط خلال %d ثوانٍ"
|
||||
|
||||
#: messages.go:195
|
||||
msgid "Permanently deleted"
|
||||
@@ -406,7 +405,7 @@ msgstr "تم التحقق بنجاح"
|
||||
|
||||
#: messages.go:198
|
||||
msgid "Successfully activated"
|
||||
msgstr "تم التنشيط بنجاح"
|
||||
msgstr "تم التفعيل بنجاح"
|
||||
|
||||
#~ msgid "Storage is full"
|
||||
#~ msgstr "التخزين ممتلئ"
|
||||
|
@@ -294,7 +294,7 @@ msgstr "Importación cancelada"
|
||||
#: messages.go:172
|
||||
#, c-format
|
||||
msgid "Indexing completed in %d s"
|
||||
msgstr "Indexación completada em %d"
|
||||
msgstr "Indexación completada en %d"
|
||||
|
||||
#: messages.go:173
|
||||
msgid "Indexing originals..."
|
||||
|
@@ -2,25 +2,25 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-03-11 19:22+0000\n"
|
||||
"PO-Revision-Date: 2025-03-11 19:36+0000\n"
|
||||
"Last-Translator: DeepL <noreply-mt-deepl@weblate.org>\n"
|
||||
"POT-Creation-Date: 2025-03-15 12:54+0000\n"
|
||||
"PO-Revision-Date: 2025-05-12 23:50+0000\n"
|
||||
"Last-Translator: Admin <hello@photoprism.app>\n"
|
||||
"Language-Team: Japanese <https://translate.photoprism.app/projects/"
|
||||
"photoprism/backend/ja/>\n"
|
||||
"Language: ja_JP\n"
|
||||
"Language: ja\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
"X-Generator: Weblate 5.9.2\n"
|
||||
"X-Generator: Weblate 5.11.1\n"
|
||||
|
||||
#: messages.go:103
|
||||
msgid "Something went wrong, try again"
|
||||
msgstr "問題が発生しました。もう一度やり直してください"
|
||||
msgstr "何かが間違っています。もう一度やり直してください"
|
||||
|
||||
#: messages.go:104
|
||||
msgid "Unable to do that"
|
||||
msgstr "実行できませんでした"
|
||||
msgstr "その操作はできません"
|
||||
|
||||
#: messages.go:105
|
||||
msgid "Changes could not be saved"
|
||||
@@ -45,7 +45,7 @@ msgstr "ファイルが見つかりませんでした"
|
||||
|
||||
#: messages.go:110
|
||||
msgid "File too large"
|
||||
msgstr "ファイルサイズが大きすぎます"
|
||||
msgstr "ファイルが大きすぎます"
|
||||
|
||||
#: messages.go:111
|
||||
msgid "Unsupported"
|
||||
@@ -53,7 +53,7 @@ msgstr "サポートされていません"
|
||||
|
||||
#: messages.go:112
|
||||
msgid "Unsupported type"
|
||||
msgstr "サポートされていないタイプ"
|
||||
msgstr "サポートされていない形式です"
|
||||
|
||||
#: messages.go:113
|
||||
msgid "Unsupported format"
|
||||
@@ -61,7 +61,7 @@ msgstr "非対応のフォーマットです"
|
||||
|
||||
#: messages.go:114
|
||||
msgid "Originals folder is empty"
|
||||
msgstr "Originalsフォルダーが空です"
|
||||
msgstr "Originals フォルダーは空です"
|
||||
|
||||
#: messages.go:115
|
||||
msgid "Selection not found"
|
||||
@@ -73,19 +73,19 @@ msgstr "エンティティが見つかりません"
|
||||
|
||||
#: messages.go:117
|
||||
msgid "Account not found"
|
||||
msgstr "アカウントは存在しません"
|
||||
msgstr "アカウントが存在しません"
|
||||
|
||||
#: messages.go:118
|
||||
msgid "User not found"
|
||||
msgstr "ユーザは存在しません"
|
||||
msgstr "ユーザーが存在しません"
|
||||
|
||||
#: messages.go:119
|
||||
msgid "Label not found"
|
||||
msgstr "ラベルは存在しません"
|
||||
msgstr "ラベルが存在しません"
|
||||
|
||||
#: messages.go:120
|
||||
msgid "Album not found"
|
||||
msgstr "アルバムは存在しません"
|
||||
msgstr "アルバムが存在しません"
|
||||
|
||||
#: messages.go:121
|
||||
msgid "Subject not found"
|
||||
@@ -113,7 +113,7 @@ msgstr "アカウントにログインしてください"
|
||||
|
||||
#: messages.go:127
|
||||
msgid "Permission denied"
|
||||
msgstr "アクセス拒否"
|
||||
msgstr "アクセスが拒否されました"
|
||||
|
||||
#: messages.go:128
|
||||
msgid "Upload might be offensive"
|
||||
@@ -121,7 +121,7 @@ msgstr "アップロードされた項目に過激なものが含まれている
|
||||
|
||||
#: messages.go:129
|
||||
msgid "Upload failed"
|
||||
msgstr "アップロード失敗"
|
||||
msgstr "アップロードに失敗しました"
|
||||
|
||||
#: messages.go:130
|
||||
msgid "No items selected"
|
||||
@@ -129,15 +129,15 @@ msgstr "項目が選択されていません"
|
||||
|
||||
#: messages.go:131
|
||||
msgid "Failed creating file, please check permissions"
|
||||
msgstr "ファイルの作成に失敗しました、権限を確認してください"
|
||||
msgstr "ファイルの作成に失敗しました。権限を確認してください"
|
||||
|
||||
#: messages.go:132
|
||||
msgid "Failed creating folder, please check permissions"
|
||||
msgstr "フォルダの作成に失敗しました、権限を確認してください"
|
||||
msgstr "フォルダの作成に失敗しました。権限を確認してください"
|
||||
|
||||
#: messages.go:133
|
||||
msgid "Could not connect, please try again"
|
||||
msgstr "接続できませんでした、再度試してみてください"
|
||||
msgstr "接続できませんでした。もう一度お試しください"
|
||||
|
||||
#: messages.go:134
|
||||
msgid "Enter verification code"
|
||||
@@ -149,7 +149,7 @@ msgstr "認証コードが無効です。もう一度お試しください"
|
||||
|
||||
#: messages.go:136
|
||||
msgid "Invalid password, please try again"
|
||||
msgstr "不正なパスワードです、再度試してみてください"
|
||||
msgstr "不正なパスワードです。もう一度お試しください"
|
||||
|
||||
#: messages.go:137
|
||||
msgid "Feature disabled"
|
||||
@@ -173,28 +173,28 @@ msgstr "zip ファイルの作成に失敗しました"
|
||||
|
||||
#: messages.go:142
|
||||
msgid "Invalid credentials"
|
||||
msgstr "不正な認証情報"
|
||||
msgstr "正しくない認証情報です"
|
||||
|
||||
#: messages.go:143
|
||||
msgid "Invalid link"
|
||||
msgstr "不正なリンク"
|
||||
msgstr "正しくないリンクです"
|
||||
|
||||
#: messages.go:144
|
||||
msgid "Invalid name"
|
||||
msgstr "無効なバケット名"
|
||||
msgstr "無効な名前です"
|
||||
|
||||
#: messages.go:145
|
||||
msgid "Busy, please try again later"
|
||||
msgstr "混雑しています、後で再試行してください"
|
||||
msgstr "他の処理中です。後で再試行してください"
|
||||
|
||||
#: messages.go:146
|
||||
#, c-format
|
||||
msgid "The wakeup interval is %s, but must be 1h or less"
|
||||
msgstr "ウェイクアップ間隔は%sであるが、1h以下でなければならない"
|
||||
msgstr "ウェイクアップ間隔は %s ですが、1時間以内で指定する必要があります"
|
||||
|
||||
#: messages.go:147
|
||||
msgid "Your account could not be connected"
|
||||
msgstr "お客様のアカウントに接続できませんでした"
|
||||
msgstr "アカウントに接続できませんでした"
|
||||
|
||||
#: messages.go:148
|
||||
msgid "Too many requests"
|
||||
@@ -202,7 +202,7 @@ msgstr "リクエストが多すぎます"
|
||||
|
||||
#: messages.go:149
|
||||
msgid "Insufficient storage"
|
||||
msgstr "ストレージ不足"
|
||||
msgstr "ストレージが不足しています"
|
||||
|
||||
#: messages.go:150
|
||||
msgid "Quota exceeded"
|
||||
@@ -214,16 +214,16 @@ msgstr "変更が正常に保存されました"
|
||||
|
||||
#: messages.go:154
|
||||
msgid "Album created"
|
||||
msgstr "アルバムを作成しました"
|
||||
msgstr "アルバムが作成されました"
|
||||
|
||||
#: messages.go:155
|
||||
msgid "Album saved"
|
||||
msgstr "アルバムを保存しました"
|
||||
msgstr "アルバムが保存されました"
|
||||
|
||||
#: messages.go:156
|
||||
#, c-format
|
||||
msgid "Album %s deleted"
|
||||
msgstr "アルバム %s を削除しました"
|
||||
msgstr "アルバム %s が削除されました"
|
||||
|
||||
#: messages.go:157
|
||||
msgid "Album contents cloned"
|
||||
@@ -298,7 +298,7 @@ msgstr "インデックスが %d 秒で完了しました"
|
||||
|
||||
#: messages.go:173
|
||||
msgid "Indexing originals..."
|
||||
msgstr "オリジナルの項目をインデックスしています..."
|
||||
msgstr "originals をインデックスしています..."
|
||||
|
||||
#: messages.go:174
|
||||
#, c-format
|
||||
@@ -338,7 +338,7 @@ msgstr "保存対象"
|
||||
|
||||
#: messages.go:182
|
||||
msgid "Subject deleted"
|
||||
msgstr "件名 削除"
|
||||
msgstr "件名を削除しました"
|
||||
|
||||
#: messages.go:183
|
||||
msgid "Person saved"
|
||||
@@ -346,11 +346,11 @@ msgstr "保存された人"
|
||||
|
||||
#: messages.go:184
|
||||
msgid "Person deleted"
|
||||
msgstr "削除された人"
|
||||
msgstr "人を削除しました"
|
||||
|
||||
#: messages.go:185
|
||||
msgid "File uploaded"
|
||||
msgstr "アップロードされたファイル"
|
||||
msgstr "ファイルがアップロードされました"
|
||||
|
||||
#: messages.go:186
|
||||
#, c-format
|
||||
@@ -363,7 +363,7 @@ msgstr "アップロードの処理..."
|
||||
|
||||
#: messages.go:188
|
||||
msgid "Upload has been processed"
|
||||
msgstr "アップロードが処理されました"
|
||||
msgstr "アップロードが完了しました"
|
||||
|
||||
#: messages.go:189
|
||||
msgid "Selection approved"
|
||||
@@ -379,7 +379,7 @@ msgstr "選択した項目が復元されました"
|
||||
|
||||
#: messages.go:192
|
||||
msgid "Selection marked as private"
|
||||
msgstr "選択した項目をプライベートにしました"
|
||||
msgstr "選択した項目がプライベートに設定されました"
|
||||
|
||||
#: messages.go:193
|
||||
msgid "Albums deleted"
|
||||
@@ -392,7 +392,7 @@ msgstr "%d 秒で zip ファイルを作成しました"
|
||||
|
||||
#: messages.go:195
|
||||
msgid "Permanently deleted"
|
||||
msgstr "永久に削除"
|
||||
msgstr "完全に削除されました"
|
||||
|
||||
#: messages.go:196
|
||||
#, c-format
|
2
assets/models/.gitignore
vendored
Normal file
2
assets/models/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
@@ -28,8 +28,8 @@
|
||||
<div class="splash-logo">
|
||||
{{template "logo.gohtml" .}}
|
||||
</div>
|
||||
<progress id="progress" class="html-progress" max="100"></progress>
|
||||
<progress id="progress" class="html-progress" role="progressbar" max="100"></progress>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="busy-overlay"><div class="splash-center"><progress id="busy-progress" class="html-progress" max="100"></progress></div></div>
|
||||
<div id="busy-overlay"><div class="splash-center"><progress id="busy-progress" class="html-progress" role="progressbar" max="100"></progress></div></div>
|
@@ -55,6 +55,8 @@ services:
|
||||
PHOTOPRISM_DISABLE_TENSORFLOW: "false" # Don't use TensorFlow for image classification
|
||||
PHOTOPRISM_DETECT_NSFW: "false" # Flag photos as private that MAY be offensive (requires TensorFlow)
|
||||
PHOTOPRISM_UPLOAD_NSFW: "false" # Allows uploads that may be offensive
|
||||
PHOTOPRISM_UPLOAD_ALLOW: "" # restricts uploads to these file types (comma-separated list of EXTENSIONS; leave blank to allow all)
|
||||
PHOTOPRISM_UPLOAD_ARCHIVES: "true" # allows upload of zip archives (will be extracted before import)
|
||||
PHOTOPRISM_DARKTABLE_PRESETS: "false" # Enables Darktable presets and disables concurrent RAW conversion
|
||||
PHOTOPRISM_THUMB_FILTER: "lanczos" # Resample filter, best to worst: blackman, lanczos, cubic, linear
|
||||
PHOTOPRISM_THUMB_UNCACHED: "true" # Enables on-demand thumbnail rendering (high memory and cpu usage)
|
||||
@@ -62,12 +64,12 @@ services:
|
||||
# PHOTOPRISM_THUMB_SIZE: 4096 # Retina 4K, DCI 4K (requires more storage); 7680 for 8K Ultra HD
|
||||
PHOTOPRISM_THUMB_SIZE_UNCACHED: 7680 # On-demand rendering size limit (default 7680, min 720, max 7680)
|
||||
PHOTOPRISM_JPEG_SIZE: 7680 # Size limit for converted image files in pixels (720-30000)
|
||||
TF_CPP_MIN_LOG_LEVEL: 0 # Show TensorFlow log messages for development
|
||||
TF_CPP_MIN_LOG_LEVEL: 1 # Show TensorFlow log messages for development
|
||||
## Enable TensorFlow AVX2 support for modern Intel CPUs (requires starting the container as root):
|
||||
# PHOTOPRISM_INIT: "tensorflow-amd64-avx2"
|
||||
## Hardware video transcoding config (optional):
|
||||
# PHOTOPRISM_FFMPEG_BUFFERS: "64" # FFmpeg capture buffers (default: 32)
|
||||
# PHOTOPRISM_FFMPEG_BITRATE: "32" # FFmpeg encoding bitrate limit in Mbit/s (default: 50)
|
||||
# PHOTOPRISM_FFMPEG_BITRATE: "32" # FFmpeg encoding bitrate limit in Mbps (default: 60)
|
||||
# PHOTOPRISM_FFMPEG_ENCODER: "h264_v4l2m2m" # Use Video4Linux for AVC transcoding (default: libx264)
|
||||
# PHOTOPRISM_FFMPEG_ENCODER: "h264_qsv" # Use Intel Quick Sync Video for AVC transcoding (default: libx264)
|
||||
# PHOTOPRISM_INIT: "intel-graphics tensorflow-amd64-avx2" # Enable TensorFlow AVX2 & Intel Graphics support
|
||||
@@ -120,8 +122,8 @@ volumes:
|
||||
go-mod:
|
||||
driver: local
|
||||
|
||||
## Create shared "photoprism-develop" network for connecting with services in other compose.yaml files
|
||||
## Create shared "photoprism" network for connecting with services in other compose.yaml files
|
||||
networks:
|
||||
default:
|
||||
name: shared
|
||||
name: photoprism
|
||||
driver: bridge
|
||||
|
190
compose.intel.yaml
Normal file
190
compose.intel.yaml
Normal file
@@ -0,0 +1,190 @@
|
||||
services:
|
||||
## PhotoPrism (Development Environment for Intel QSV hardware transcoding)
|
||||
photoprism:
|
||||
build: .
|
||||
image: photoprism/photoprism:develop
|
||||
depends_on:
|
||||
- mariadb
|
||||
- dummy-webdav
|
||||
- dummy-oidc
|
||||
stop_grace_period: 15s
|
||||
privileged: true
|
||||
security_opt:
|
||||
- seccomp:unconfined
|
||||
- apparmor:unconfined
|
||||
## Expose HTTP and debug ports
|
||||
ports:
|
||||
- "2342:2342" # Default HTTP port (host:container)
|
||||
- "2443:2443" # Default TLS port (host:container)
|
||||
- "2343:2343" # Acceptance Test HTTP port (host:container)
|
||||
- "40000:40000" # Go Debugger (host:container)
|
||||
shm_size: "2gb"
|
||||
## Set links and labels for use with Traefik reverse proxy
|
||||
links:
|
||||
- "traefik:localssl.dev"
|
||||
- "traefik:app.localssl.dev"
|
||||
- "traefik:keycloak.localssl.dev"
|
||||
- "traefik:dummy-oidc.localssl.dev"
|
||||
- "traefik:dummy-webdav.localssl.dev"
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=photoprism"
|
||||
- "traefik.http.services.photoprism.loadbalancer.server.port=2342"
|
||||
- "traefik.http.services.photoprism.loadbalancer.server.scheme=http"
|
||||
- "traefik.http.routers.photoprism.entrypoints=websecure"
|
||||
- "traefik.http.routers.photoprism.rule=Host(`localssl.dev`) || HostRegexp(`^.+\\.localssl\\.dev`)"
|
||||
- "traefik.http.routers.photoprism.priority=2"
|
||||
- "traefik.http.routers.photoprism.tls.domains[0].main=localssl.dev"
|
||||
- "traefik.http.routers.photoprism.tls.domains[0].sans=*.localssl.dev"
|
||||
- "traefik.http.routers.photoprism.tls=true"
|
||||
## Configure development environment
|
||||
environment:
|
||||
## Run as a non-root user after initialization (supported: 0, 33, 50-99, 500-600, and 900-1200):
|
||||
PHOTOPRISM_UID: ${UID:-1000} # user id, should match your host user id
|
||||
PHOTOPRISM_GID: ${GID:-1000} # group id
|
||||
## Access Management:
|
||||
PHOTOPRISM_ADMIN_USER: "admin" # admin login username
|
||||
PHOTOPRISM_ADMIN_PASSWORD: "photoprism" # initial admin password (8-72 characters)
|
||||
PHOTOPRISM_AUTH_MODE: "password" # authentication mode (public, password)
|
||||
PHOTOPRISM_REGISTER_URI: "https://keycloak.localssl.dev/admin/"
|
||||
PHOTOPRISM_PASSWORD_RESET_URI: "https://keycloak.localssl.dev/realms/master/login-actions/reset-credentials"
|
||||
PHOTOPRISM_USAGE_INFO: "true"
|
||||
PHOTOPRISM_FILES_QUOTA: "100"
|
||||
## Customization:
|
||||
PHOTOPRISM_DEFAULT_LOCALE: "en" # default user interface language, e.g. "en" or "de"
|
||||
PHOTOPRISM_PLACES_LOCALE: "local" # location details language, e.g. "local", "en", or
|
||||
## OpenID Connect (pre-configured for local tests):
|
||||
## see https://keycloak.localssl.dev/realms/master/.well-known/openid-configuration
|
||||
PHOTOPRISM_OIDC_URI: "https://keycloak.localssl.dev/realms/master"
|
||||
PHOTOPRISM_OIDC_CLIENT: "photoprism-develop"
|
||||
PHOTOPRISM_OIDC_SECRET: "9d8351a0-ca01-4556-9c37-85eb634869b9"
|
||||
PHOTOPRISM_OIDC_PROVIDER: "Keycloak"
|
||||
PHOTOPRISM_OIDC_REGISTER: "true"
|
||||
PHOTOPRISM_OIDC_WEBDAV: "true"
|
||||
PHOTOPRISM_DISABLE_OIDC: "false"
|
||||
## LDAP Authentication (pre-configured for local tests):
|
||||
PHOTOPRISM_LDAP_URI: "ldap://dummy-ldap:389"
|
||||
PHOTOPRISM_LDAP_INSECURE: "true"
|
||||
PHOTOPRISM_LDAP_SYNC: "true"
|
||||
PHOTOPRISM_LDAP_BIND: "simple"
|
||||
PHOTOPRISM_LDAP_BIND_DN: "cn"
|
||||
PHOTOPRISM_LDAP_BASE_DN: "dc=localssl,dc=dev"
|
||||
PHOTOPRISM_LDAP_ROLE: ""
|
||||
PHOTOPRISM_LDAP_ROLE_DN: "ou=photoprism-*,ou=groups,dc=localssl,dc=dev"
|
||||
PHOTOPRISM_LDAP_WEBDAV_DN: "ou=photoprism-webdav,ou=groups,dc=localssl,dc=dev"
|
||||
## HTTPS/TLS Options:
|
||||
## see https://docs.photoprism.app/getting-started/using-https/
|
||||
PHOTOPRISM_DISABLE_TLS: "true"
|
||||
PHOTOPRISM_DEFAULT_TLS: "true"
|
||||
## Site Information:
|
||||
PHOTOPRISM_SITE_URL: "https://app.localssl.dev/" # server URL in the format "http(s)://domain.name(:port)/(path)"
|
||||
PHOTOPRISM_SITE_CAPTION: "AI-Powered Photos App"
|
||||
PHOTOPRISM_SITE_DESCRIPTION: "Tags and finds pictures without getting in your way!"
|
||||
PHOTOPRISM_SITE_AUTHOR: "@photoprism_app"
|
||||
PHOTOPRISM_DEBUG: "true"
|
||||
PHOTOPRISM_READONLY: "false"
|
||||
PHOTOPRISM_EXPERIMENTAL: "true"
|
||||
PHOTOPRISM_HTTP_MODE: "debug"
|
||||
PHOTOPRISM_HTTP_HOST: "0.0.0.0"
|
||||
PHOTOPRISM_HTTP_PORT: 2342
|
||||
PHOTOPRISM_HTTP_COMPRESSION: "gzip" # improves transfer speed and bandwidth utilization (none or gzip)
|
||||
PHOTOPRISM_DATABASE_DRIVER: "mysql"
|
||||
PHOTOPRISM_DATABASE_SERVER: "mariadb:4001"
|
||||
PHOTOPRISM_DATABASE_NAME: "photoprism"
|
||||
PHOTOPRISM_DATABASE_USER: "root"
|
||||
PHOTOPRISM_DATABASE_PASSWORD: "photoprism"
|
||||
PHOTOPRISM_TEST_DRIVER: "sqlite"
|
||||
# PHOTOPRISM_TEST_DSN_MYSQL8: "root:photoprism@tcp(mysql:4001)/photoprism?charset=utf8mb4,utf8&collation=utf8mb4_unicode_ci&parseTime=true&timeout=15s"
|
||||
PHOTOPRISM_ASSETS_PATH: "/go/src/github.com/photoprism/photoprism/assets"
|
||||
PHOTOPRISM_STORAGE_PATH: "/go/src/github.com/photoprism/photoprism/storage"
|
||||
PHOTOPRISM_ORIGINALS_PATH: "/go/src/github.com/photoprism/photoprism/storage/originals"
|
||||
PHOTOPRISM_ORIGINALS_LIMIT: 128000 # sets originals file size limit to 128 GB
|
||||
PHOTOPRISM_IMPORT_PATH: "/go/src/github.com/photoprism/photoprism/storage/import"
|
||||
PHOTOPRISM_DISABLE_CHOWN: "false" # disables updating storage permissions via chmod and chown on startup
|
||||
PHOTOPRISM_DISABLE_BACKUPS: "false" # disables backing up albums and photo metadata to YAML files
|
||||
PHOTOPRISM_DISABLE_WEBDAV: "false" # disables built-in WebDAV server
|
||||
PHOTOPRISM_DISABLE_SETTINGS: "false" # disables settings UI and API
|
||||
PHOTOPRISM_DISABLE_PLACES: "false" # disables reverse geocoding and maps
|
||||
PHOTOPRISM_DISABLE_EXIFTOOL: "false" # disables creating JSON metadata sidecar files with ExifTool
|
||||
PHOTOPRISM_DISABLE_TENSORFLOW: "false" # disables all features depending on TensorFlow
|
||||
PHOTOPRISM_DISABLE_RAW: "false" # disables indexing and conversion of RAW images
|
||||
PHOTOPRISM_RAW_PRESETS: "false" # enables applying user presets when converting RAW images (reduces performance)
|
||||
PHOTOPRISM_DETECT_NSFW: "false" # automatically flags photos as private that MAY be offensive (requires TensorFlow)
|
||||
PHOTOPRISM_UPLOAD_NSFW: "false" # allows uploads that MAY be offensive (no effect without TensorFlow)
|
||||
PHOTOPRISM_UPLOAD_ALLOW: "" # restricts uploads to these file types (comma-separated list of EXTENSIONS; leave blank to allow all)
|
||||
PHOTOPRISM_UPLOAD_ARCHIVES: "true" # allows upload of zip archives (will be extracted before import)
|
||||
PHOTOPRISM_THUMB_LIBRARY: "auto" # image processing library to be used for generating thumbnails (auto, imaging, vips)
|
||||
PHOTOPRISM_THUMB_FILTER: "auto" # downscaling filter (imaging best to worst: blackman, lanczos, cubic, linear, nearest)
|
||||
PHOTOPRISM_THUMB_UNCACHED: "true" # enables on-demand thumbnail rendering (high memory and cpu usage)
|
||||
## Intel Quick Sync Video (QSV) (https://docs.photoprism.app/getting-started/advanced/transcoding/#intel-quick-sync):
|
||||
PHOTOPRISM_FFMPEG_ENCODER: "intel" # H.264/AVC encoder (software, intel, nvidia, apple, raspberry, or vaapi)
|
||||
PHOTOPRISM_FFMPEG_SIZE: "1920" # video size limit in pixels (720-7680) (default: 3840)
|
||||
# PHOTOPRISM_FFMPEG_BITRATE: "64" # video bitrate limit in Mbps (default: 60)
|
||||
## Run/install on first startup (options: update tensorflow https intel gpu davfs yt-dlp):
|
||||
PHOTOPRISM_INIT: "https intel tensorflow"
|
||||
## External dependencies and tools:
|
||||
TF_CPP_MIN_LOG_LEVEL: 1
|
||||
GOCACHE: "/go/src/github.com/photoprism/photoprism/.local/gocache"
|
||||
CODEX_HOME: "/go/src/github.com/photoprism/photoprism/.local/codex"
|
||||
## Share hardware devices with FFmpeg for hardware video transcoding:
|
||||
devices:
|
||||
- "/dev/dri:/dev/dri"
|
||||
working_dir: "/go/src/github.com/photoprism/photoprism"
|
||||
volumes:
|
||||
- ".:/go/src/github.com/photoprism/photoprism"
|
||||
- "./storage:/photoprism"
|
||||
- "go-mod:/go/pkg/mod"
|
||||
|
||||
mariadb:
|
||||
extends:
|
||||
file: ./compose.yaml
|
||||
service: mariadb
|
||||
qdrant:
|
||||
extends:
|
||||
file: ./compose.yaml
|
||||
service: qdrant
|
||||
photoprism-vision:
|
||||
extends:
|
||||
file: ./compose.yaml
|
||||
service: photoprism-vision
|
||||
ollama:
|
||||
extends:
|
||||
file: ./compose.yaml
|
||||
service: ollama
|
||||
traefik:
|
||||
extends:
|
||||
file: ./compose.yaml
|
||||
service: traefik
|
||||
dummy-webdav:
|
||||
extends:
|
||||
file: ./compose.yaml
|
||||
service: dummy-webdav
|
||||
dummy-oidc:
|
||||
extends:
|
||||
file: ./compose.yaml
|
||||
service: dummy-oidc
|
||||
dummy-ldap:
|
||||
extends:
|
||||
file: ./compose.yaml
|
||||
service: dummy-ldap
|
||||
keycloak:
|
||||
extends:
|
||||
file: ./compose.yaml
|
||||
service: keycloak
|
||||
prometheus:
|
||||
extends:
|
||||
file: ./compose.yaml
|
||||
service: prometheus
|
||||
|
||||
## Create named volume for Go module cache
|
||||
volumes:
|
||||
go-mod:
|
||||
driver: local
|
||||
mariadb:
|
||||
driver: local
|
||||
|
||||
## Create shared "photoprism" network for connecting with services in other compose.yaml files
|
||||
networks:
|
||||
default:
|
||||
name: photoprism
|
||||
driver: bridge
|
@@ -12,6 +12,7 @@ services:
|
||||
- "2344:2342" # HTTP port (host:container)
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=photoprism"
|
||||
- "traefik.http.services.latest.loadbalancer.server.port=2342"
|
||||
- "traefik.http.routers.latest.entrypoints=websecure"
|
||||
- "traefik.http.routers.latest.rule=Host(`latest.localssl.dev`)"
|
||||
@@ -50,6 +51,8 @@ services:
|
||||
PHOTOPRISM_DISABLE_TENSORFLOW: "false" # disables all features depending on TensorFlow
|
||||
PHOTOPRISM_DETECT_NSFW: "false" # automatically flags photos as private that MAY be offensive (requires TensorFlow)
|
||||
PHOTOPRISM_UPLOAD_NSFW: "false" # allows uploads that MAY be offensive (no effect without TensorFlow)
|
||||
PHOTOPRISM_UPLOAD_ALLOW: "" # restricts uploads to these file types (comma-separated list of EXTENSIONS; leave blank to allow all)
|
||||
PHOTOPRISM_UPLOAD_ARCHIVES: "true" # allows upload of zip archives (will be extracted before import)
|
||||
PHOTOPRISM_RAW_PRESETS: "false" # enables applying user presets when converting RAW images (reduces performance)
|
||||
PHOTOPRISM_THUMB_FILTER: "lanczos" # resample filter, best to worst: blackman, lanczos, cubic, linear
|
||||
PHOTOPRISM_THUMB_UNCACHED: "true" # enables on-demand thumbnail rendering (high memory and cpu usage)
|
||||
@@ -57,13 +60,13 @@ services:
|
||||
# PHOTOPRISM_THUMB_SIZE: 4096 # Retina 4K, DCI 4K (requires more storage); 7680 for 8K Ultra HD
|
||||
PHOTOPRISM_THUMB_SIZE_UNCACHED: 7680 # on-demand rendering size limit (default 7680, min 720, max 7680)
|
||||
PHOTOPRISM_JPEG_SIZE: 7680 # size limit for converted image files in pixels (720-30000)
|
||||
TF_CPP_MIN_LOG_LEVEL: 0 # show TensorFlow log messages for development
|
||||
TF_CPP_MIN_LOG_LEVEL: 1 # show TensorFlow log messages for development
|
||||
working_dir: "/photoprism"
|
||||
volumes:
|
||||
- "./storage:/photoprism/storage"
|
||||
- "./storage/originals:/photoprism/originals"
|
||||
|
||||
## Join shared "photoprism-develop" network
|
||||
## Join shared "photoprism" network
|
||||
networks:
|
||||
default:
|
||||
name: photoprism
|
||||
|
@@ -6,7 +6,7 @@ services:
|
||||
## Docs: https://docs.photoprism.org/
|
||||
photoprism-local:
|
||||
image: photoprism/photoprism:local
|
||||
stop_grace_period: 10s
|
||||
stop_grace_period: 15s
|
||||
security_opt:
|
||||
- seccomp:unconfined
|
||||
- apparmor:unconfined
|
||||
@@ -14,6 +14,7 @@ services:
|
||||
- "2345:2342" # HTTP port (host:container)
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=photoprism"
|
||||
- "traefik.http.services.latest.loadbalancer.server.port=2342"
|
||||
- "traefik.http.routers.latest.entrypoints=websecure"
|
||||
- "traefik.http.routers.latest.rule=Host(`local.localssl.dev`)"
|
||||
@@ -51,6 +52,8 @@ services:
|
||||
PHOTOPRISM_DISABLE_TENSORFLOW: "false" # disables all features depending on TensorFlow
|
||||
PHOTOPRISM_DETECT_NSFW: "false" # automatically flags photos as private that MAY be offensive (requires TensorFlow)
|
||||
PHOTOPRISM_UPLOAD_NSFW: "false" # allows uploads that MAY be offensive (no effect without TensorFlow)
|
||||
PHOTOPRISM_UPLOAD_ALLOW: "" # restricts uploads to these file types (comma-separated list of EXTENSIONS; leave blank to allow all)
|
||||
PHOTOPRISM_UPLOAD_ARCHIVES: "true" # allows upload of zip archives (will be extracted before import)
|
||||
PHOTOPRISM_RAW_PRESETS: "false" # enables applying user presets when converting RAW images (reduces performance)
|
||||
PHOTOPRISM_THUMB_FILTER: "lanczos" # resample filter, best to worst: blackman, lanczos, cubic, linear
|
||||
PHOTOPRISM_THUMB_UNCACHED: "true" # enables on-demand thumbnail rendering (high memory and cpu usage)
|
||||
@@ -58,8 +61,8 @@ services:
|
||||
# PHOTOPRISM_THUMB_SIZE: 4096 # Retina 4K, DCI 4K (requires more storage); 7680 for 8K Ultra HD
|
||||
PHOTOPRISM_THUMB_SIZE_UNCACHED: 7680 # on-demand rendering size limit (default 7680, min 720, max 7680)
|
||||
PHOTOPRISM_JPEG_SIZE: 7680 # size limit for converted image files in pixels (720-30000)
|
||||
TF_CPP_MIN_LOG_LEVEL: 0 # show TensorFlow log messages for development
|
||||
# PHOTOPRISM_INIT: "http gpu tensorflow" # Options: "update https gpu tensorflow davfs clitools clean"
|
||||
TF_CPP_MIN_LOG_LEVEL: 1 # show TensorFlow log messages for development
|
||||
# PHOTOPRISM_INIT: "http gpu tensorflow yt-dlp" # Options: "update https gpu tensorflow davfs clitools clean"
|
||||
PHOTOPRISM_FFMPEG_ENCODER: "nvidia" # Options: "software", "intel", "nvidia", "apple", "raspberry"
|
||||
PHOTOPRISM_STORAGE_PATH: "/photoprism/storage"
|
||||
PHOTOPRISM_ORIGINALS_PATH: "/photoprism/storage/originals"
|
||||
@@ -70,7 +73,7 @@ services:
|
||||
volumes:
|
||||
- "./storage:/photoprism/storage"
|
||||
|
||||
## Join shared "photoprism-develop" network
|
||||
## Join shared "photoprism" network
|
||||
networks:
|
||||
default:
|
||||
name: photoprism
|
||||
|
@@ -145,7 +145,7 @@ services:
|
||||
MYSQL_PASSWORD: "photoprism"
|
||||
MYSQL_ROOT_PASSWORD: "photoprism"
|
||||
|
||||
## Join shared "photoprism-develop" network
|
||||
## Join shared "photoprism" network
|
||||
networks:
|
||||
default:
|
||||
name: photoprism
|
||||
|
@@ -15,7 +15,7 @@ services:
|
||||
MYSQL_PASSWORD: "photoprism"
|
||||
MYSQL_ROOT_PASSWORD: "photoprism"
|
||||
|
||||
## Join shared "photoprism-develop" network
|
||||
## Join shared "photoprism" network
|
||||
networks:
|
||||
default:
|
||||
name: photoprism
|
||||
|
@@ -3,11 +3,13 @@ services:
|
||||
photoprism:
|
||||
build: .
|
||||
image: photoprism/photoprism:develop
|
||||
runtime: nvidia
|
||||
depends_on:
|
||||
- mariadb
|
||||
- dummy-webdav
|
||||
- dummy-oidc
|
||||
stop_grace_period: 10s
|
||||
stop_grace_period: 15s
|
||||
privileged: true
|
||||
security_opt:
|
||||
- seccomp:unconfined
|
||||
- apparmor:unconfined
|
||||
@@ -22,11 +24,14 @@ services:
|
||||
links:
|
||||
- "traefik:localssl.dev"
|
||||
- "traefik:app.localssl.dev"
|
||||
- "traefik:vision.localssl.dev"
|
||||
- "traefik:qdrant.localssl.dev"
|
||||
- "traefik:keycloak.localssl.dev"
|
||||
- "traefik:dummy-oidc.localssl.dev"
|
||||
- "traefik:dummy-webdav.localssl.dev"
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=photoprism"
|
||||
- "traefik.http.services.photoprism.loadbalancer.server.port=2342"
|
||||
- "traefik.http.services.photoprism.loadbalancer.server.scheme=http"
|
||||
- "traefik.http.routers.photoprism.entrypoints=websecure"
|
||||
@@ -48,6 +53,9 @@ services:
|
||||
PHOTOPRISM_PASSWORD_RESET_URI: "https://keycloak.localssl.dev/realms/master/login-actions/reset-credentials"
|
||||
PHOTOPRISM_USAGE_INFO: "true"
|
||||
PHOTOPRISM_FILES_QUOTA: "100"
|
||||
## Customization:
|
||||
PHOTOPRISM_DEFAULT_LOCALE: "en" # default user interface language, e.g. "en" or "de"
|
||||
PHOTOPRISM_PLACES_LOCALE: "local" # location details language, e.g. "local", "en", or
|
||||
## OpenID Connect (pre-configured for local tests):
|
||||
## see https://keycloak.localssl.dev/realms/master/.well-known/openid-configuration
|
||||
PHOTOPRISM_OIDC_URI: "https://keycloak.localssl.dev/realms/master"
|
||||
@@ -106,44 +114,116 @@ services:
|
||||
PHOTOPRISM_RAW_PRESETS: "false" # enables applying user presets when converting RAW images (reduces performance)
|
||||
PHOTOPRISM_DETECT_NSFW: "false" # automatically flags photos as private that MAY be offensive (requires TensorFlow)
|
||||
PHOTOPRISM_UPLOAD_NSFW: "false" # allows uploads that MAY be offensive (no effect without TensorFlow)
|
||||
PHOTOPRISM_UPLOAD_ALLOW: "" # restricts uploads to these file types (comma-separated list of EXTENSIONS; leave blank to allow all)
|
||||
PHOTOPRISM_UPLOAD_ARCHIVES: "true" # allows upload of zip archives (will be extracted before import)
|
||||
PHOTOPRISM_THUMB_LIBRARY: "auto" # image processing library to be used for generating thumbnails (auto, imaging, vips)
|
||||
PHOTOPRISM_THUMB_FILTER: "auto" # downscaling filter (imaging best to worst: blackman, lanczos, cubic, linear, nearest)
|
||||
PHOTOPRISM_THUMB_UNCACHED: "true" # enables on-demand thumbnail rendering (high memory and cpu usage)
|
||||
TF_CPP_MIN_LOG_LEVEL: 0 # show TensorFlow log messages for development
|
||||
## Nvidia Video Transcoding (https://docs.photoprism.app/getting-started/advanced/transcoding/#nvidia-container-toolkit):
|
||||
## Run/install on first startup (options: update tensorflow https intel gpu davfs yt-dlp):
|
||||
PHOTOPRISM_INIT: "https tensorflow-gpu"
|
||||
## Computer Vision API (https://docs.photoprism.app/getting-started/config-options/#computer-vision):
|
||||
PHOTOPRISM_VISION_API: "true" # server: enables service API endpoints under /api/v1/vision (requires access token)
|
||||
PHOTOPRISM_VISION_URI: "" # client: service URI, e.g. http://hostname/api/v1/vision (leave blank to disable)
|
||||
PHOTOPRISM_VISION_KEY: "" # client: service access token (for authentication)
|
||||
## NVIDIA GPU Hardware Acceleration (see https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html):
|
||||
NVIDIA_VISIBLE_DEVICES: "all"
|
||||
NVIDIA_DRIVER_CAPABILITIES: "compute,video,utility"
|
||||
NVIDIA_DRIVER_CAPABILITIES: "all"
|
||||
PHOTOPRISM_FFMPEG_ENCODER: "nvidia" # H.264/AVC encoder (software, intel, nvidia, apple, raspberry, or vaapi)
|
||||
PHOTOPRISM_FFMPEG_SIZE: "1920" # video size limit in pixels (720-7680) (default: 3840)
|
||||
PHOTOPRISM_FFMPEG_BITRATE: "50" # video bitrate limit in Mbit/s (default: 50)
|
||||
## Run/install on first startup (options: update https gpu ffmpeg tensorflow davfs clitools clean):
|
||||
PHOTOPRISM_INIT: "https tensorflow"
|
||||
## Share hardware devices with FFmpeg and TensorFlow (optional):
|
||||
PHOTOPRISM_FFMPEG_BITRATE: "64" # video bitrate limit in Mbps (default: 60)
|
||||
## External dependencies and tools:
|
||||
TF_CPP_MIN_LOG_LEVEL: 1
|
||||
GOCACHE: "/go/src/github.com/photoprism/photoprism/.local/gocache"
|
||||
CODEX_HOME: "/go/src/github.com/photoprism/photoprism/.local/codex"
|
||||
## Shared devices for video hardware transcoding (optional):
|
||||
# devices:
|
||||
# - "/dev/dri:/dev/dri" # Intel QSV (Broadwell and later) or VAAPI (Haswell and earlier)
|
||||
# - "/dev/nvidia0:/dev/nvidia0" # Nvidia CUDA
|
||||
# - "/dev/nvidiactl:/dev/nvidiactl"
|
||||
# - "/dev/nvidia-modeset:/dev/nvidia-modeset"
|
||||
# - "/dev/nvidia-nvswitchctl:/dev/nvidia-nvswitchctl"
|
||||
# - "/dev/nvidia-uvm:/dev/nvidia-uvm"
|
||||
# - "/dev/nvidia-uvm-tools:/dev/nvidia-uvm-tools"
|
||||
# - "/dev/dri:/dev/dri" # Required Intel QSV or VAAPI hardware transcoding
|
||||
# - "/dev/video11:/dev/video11" # Video4Linux Video Encode Device (h264_v4l2m2m)
|
||||
working_dir: "/go/src/github.com/photoprism/photoprism"
|
||||
volumes:
|
||||
- ".:/go/src/github.com/photoprism/photoprism"
|
||||
- "./storage:/photoprism"
|
||||
- "go-mod:/go/pkg/mod"
|
||||
## NVIDIA GPU Hardware Acceleration (see https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html):
|
||||
deploy:
|
||||
resources:
|
||||
reservations:
|
||||
devices:
|
||||
- driver: "nvidia"
|
||||
capabilities: [gpu]
|
||||
count: "all"
|
||||
|
||||
## Ollama Large-Language Model Runner
|
||||
## run "ollama pull [name]:[version]" to download a vision model
|
||||
## listed at <https://ollama.com/search?c=vision>, for example:
|
||||
## docker compose exec ollama ollama pull gemma3:latest
|
||||
ollama:
|
||||
image: ollama/ollama:latest
|
||||
restart: unless-stopped
|
||||
stop_grace_period: 15s
|
||||
## Only starts this service if the "all", "ollama", or "vision" profile is specified::
|
||||
## docker compose --profile ollama up -d
|
||||
profiles: ["all", "ollama", "vision"]
|
||||
## Insecurely exposes the Ollama service on port 11434
|
||||
## without authentication (for private networks only):
|
||||
# ports:
|
||||
# - "11434:11434"
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=photoprism"
|
||||
- "traefik.http.services.ollama.loadbalancer.server.port=11434"
|
||||
- "traefik.http.routers.ollama.rule=Host(`ollama.localssl.dev`)"
|
||||
- "traefik.http.routers.ollama.entrypoints=websecure"
|
||||
- "traefik.http.routers.ollama.tls=true"
|
||||
environment:
|
||||
## Ollama Configuration Options:
|
||||
OLLAMA_HOST: "0.0.0.0:11434"
|
||||
OLLAMA_MODELS: "/root/.ollama" # model storage path (see volumes section below)
|
||||
OLLAMA_MAX_QUEUE: "100" # maximum number of queued requests
|
||||
OLLAMA_NUM_PARALLEL: "1" # maximum number of parallel requests
|
||||
OLLAMA_MAX_LOADED_MODELS: "1" # maximum number of loaded models per GPU
|
||||
OLLAMA_LOAD_TIMEOUT: "5m" # maximum time for loading models (default "5m")
|
||||
OLLAMA_KEEP_ALIVE: "5m" # duration that models stay loaded in memory (default "5m")
|
||||
OLLAMA_CONTEXT_LENGTH: "4096" # maximum input context length
|
||||
OLLAMA_MULTIUSER_CACHE: "false" # optimize prompt caching for multi-user scenarios
|
||||
OLLAMA_NOPRUNE: "false" # disables pruning of model blobs at startup
|
||||
OLLAMA_NOHISTORY: "true" # disables readline history
|
||||
OLLAMA_FLASH_ATTENTION: "false" # enables the experimental flash attention feature
|
||||
OLLAMA_KV_CACHE_TYPE: "f16" # cache quantization (f16, q8_0, or q4_0)
|
||||
OLLAMA_SCHED_SPREAD: "false" # allows scheduling models across all GPUs.
|
||||
OLLAMA_NEW_ENGINE: "true" # enables the new Ollama engine
|
||||
# OLLAMA_DEBUG: "true" # shows additional debug information
|
||||
# OLLAMA_INTEL_GPU: "true" # enables experimental Intel GPU detection
|
||||
## NVIDIA GPU Hardware Acceleration (see https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html):
|
||||
NVIDIA_VISIBLE_DEVICES: "all"
|
||||
NVIDIA_DRIVER_CAPABILITIES: "compute,utility"
|
||||
volumes:
|
||||
- "./storage/services/ollama:/root/.ollama"
|
||||
## NVIDIA GPU Hardware Acceleration (see https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html):
|
||||
deploy:
|
||||
resources:
|
||||
reservations:
|
||||
devices:
|
||||
- driver: "nvidia"
|
||||
count: 1
|
||||
capabilities: [ gpu ]
|
||||
count: "all"
|
||||
|
||||
mariadb:
|
||||
extends:
|
||||
file: ./compose.yaml
|
||||
service: mariadb
|
||||
qdrant:
|
||||
extends:
|
||||
file: ./compose.yaml
|
||||
service: qdrant
|
||||
open-webui:
|
||||
extends:
|
||||
file: ./compose.yaml
|
||||
service: open-webui
|
||||
photoprism-vision:
|
||||
extends:
|
||||
file: ./compose.yaml
|
||||
service: photoprism-vision
|
||||
traefik:
|
||||
extends:
|
||||
file: ./compose.yaml
|
||||
@@ -176,7 +256,7 @@ volumes:
|
||||
mariadb:
|
||||
driver: local
|
||||
|
||||
## Create shared "photoprism-develop" network for connecting with services in other compose.yaml files
|
||||
## Create shared "photoprism" network for connecting with services in other compose.yaml files
|
||||
networks:
|
||||
default:
|
||||
name: photoprism
|
||||
|
@@ -24,7 +24,6 @@ services:
|
||||
- "go-mod:/go/pkg/mod"
|
||||
shm_size: "2gb"
|
||||
environment:
|
||||
PHOTOPRISM_INIT: "https"
|
||||
PHOTOPRISM_ADMIN_USER: "admin" # admin login username
|
||||
PHOTOPRISM_ADMIN_PASSWORD: "photoprism" # initial admin password (8-72 characters)
|
||||
PHOTOPRISM_AUTH_MODE: "password" # authentication mode (public, password)
|
||||
@@ -58,6 +57,8 @@ services:
|
||||
PHOTOPRISM_DISABLE_TENSORFLOW: "false" # disables all features depending on TensorFlow
|
||||
PHOTOPRISM_DETECT_NSFW: "false" # automatically flags photos as private that MAY be offensive (requires TensorFlow)
|
||||
PHOTOPRISM_UPLOAD_NSFW: "false" # allows uploads that MAY be offensive (no effect without TensorFlow)
|
||||
PHOTOPRISM_UPLOAD_ALLOW: "" # restricts uploads to these file types (comma-separated list of EXTENSIONS; leave blank to allow all)
|
||||
PHOTOPRISM_UPLOAD_ARCHIVES: "true" # allows upload of zip archives (will be extracted before import)
|
||||
PHOTOPRISM_RAW_PRESETS: "false" # enables applying user presets when converting RAW images (reduces performance)
|
||||
PHOTOPRISM_THUMB_FILTER: "lanczos" # resample filter, best to worst: blackman, lanczos, cubic, linear
|
||||
PHOTOPRISM_THUMB_UNCACHED: "true" # enables on-demand thumbnail rendering (high memory and cpu usage)
|
||||
@@ -65,8 +66,12 @@ services:
|
||||
# PHOTOPRISM_THUMB_SIZE: 4096 # Retina 4K, DCI 4K (requires more storage); 7680 for 8K Ultra HD
|
||||
PHOTOPRISM_THUMB_SIZE_UNCACHED: 7680 # on-demand rendering size limit (default 7680, min 720, max 7680)
|
||||
PHOTOPRISM_JPEG_SIZE: 7680 # size limit for converted image files in pixels (720-30000)
|
||||
TF_CPP_MIN_LOG_LEVEL: 0 # show TensorFlow log messages for development
|
||||
|
||||
## Run/install on first startup (options: update tensorflow https intel gpu davfs yt-dlp):
|
||||
PHOTOPRISM_INIT: "https"
|
||||
## External dependencies and tools:
|
||||
TF_CPP_MIN_LOG_LEVEL: 1
|
||||
GOCACHE: "/go/src/github.com/photoprism/photoprism/.local/gocache"
|
||||
CODEX_HOME: "/go/src/github.com/photoprism/photoprism/.local/codex"
|
||||
## PostgreSQL Database Server
|
||||
## Docs: https://www.postgresql.org/docs/
|
||||
postgres:
|
||||
|
@@ -12,6 +12,7 @@ services:
|
||||
- "2344:2342" # HTTP port (host:container)
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=photoprism"
|
||||
- "traefik.http.services.preview.loadbalancer.server.port=2342"
|
||||
- "traefik.http.routers.preview.entrypoints=websecure"
|
||||
- "traefik.http.routers.preview.rule=Host(`preview.localssl.dev`)"
|
||||
@@ -50,6 +51,8 @@ services:
|
||||
PHOTOPRISM_DISABLE_TENSORFLOW: "false" # disables all features depending on TensorFlow
|
||||
PHOTOPRISM_DETECT_NSFW: "false" # automatically flags photos as private that MAY be offensive (requires TensorFlow)
|
||||
PHOTOPRISM_UPLOAD_NSFW: "false" # allows uploads that MAY be offensive (no effect without TensorFlow)
|
||||
PHOTOPRISM_UPLOAD_ALLOW: "" # restricts uploads to these file types (comma-separated list of EXTENSIONS; leave blank to allow all)
|
||||
PHOTOPRISM_UPLOAD_ARCHIVES: "true" # allows upload of zip archives (will be extracted before import)
|
||||
PHOTOPRISM_RAW_PRESETS: "false" # enables applying user presets when converting RAW images (reduces performance)
|
||||
PHOTOPRISM_THUMB_FILTER: "lanczos" # resample filter, best to worst: blackman, lanczos, cubic, linear
|
||||
PHOTOPRISM_THUMB_UNCACHED: "true" # enables on-demand thumbnail rendering (high memory and cpu usage)
|
||||
@@ -57,13 +60,13 @@ services:
|
||||
# PHOTOPRISM_THUMB_SIZE: 4096 # Retina 4K, DCI 4K (requires more storage); 7680 for 8K Ultra HD
|
||||
PHOTOPRISM_THUMB_SIZE_UNCACHED: 7680 # on-demand rendering size limit (default 7680, min 720, max 7680)
|
||||
PHOTOPRISM_JPEG_SIZE: 7680 # size limit for converted image files in pixels (720-30000)
|
||||
TF_CPP_MIN_LOG_LEVEL: 0 # show TensorFlow log messages for development
|
||||
TF_CPP_MIN_LOG_LEVEL: 1 # show TensorFlow log messages for development
|
||||
working_dir: "/photoprism"
|
||||
volumes:
|
||||
- "./storage:/photoprism/storage"
|
||||
- "./storage/originals:/photoprism/originals"
|
||||
|
||||
## Join shared "photoprism-develop" network
|
||||
## Join shared "photoprism" network
|
||||
networks:
|
||||
default:
|
||||
name: photoprism
|
||||
|
185
compose.yaml
185
compose.yaml
@@ -10,7 +10,7 @@ services:
|
||||
- mariadb
|
||||
- dummy-webdav
|
||||
- dummy-oidc
|
||||
stop_grace_period: 10s
|
||||
stop_grace_period: 15s
|
||||
security_opt:
|
||||
- seccomp:unconfined
|
||||
- apparmor:unconfined
|
||||
@@ -25,11 +25,14 @@ services:
|
||||
links:
|
||||
- "traefik:localssl.dev"
|
||||
- "traefik:app.localssl.dev"
|
||||
- "traefik:vision.localssl.dev"
|
||||
- "traefik:qdrant.localssl.dev"
|
||||
- "traefik:keycloak.localssl.dev"
|
||||
- "traefik:dummy-oidc.localssl.dev"
|
||||
- "traefik:dummy-webdav.localssl.dev"
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=photoprism"
|
||||
- "traefik.http.services.photoprism.loadbalancer.server.port=2342"
|
||||
- "traefik.http.services.photoprism.loadbalancer.server.scheme=http"
|
||||
- "traefik.http.routers.photoprism.entrypoints=websecure"
|
||||
@@ -55,6 +58,9 @@ services:
|
||||
PHOTOPRISM_PASSWORD_RESET_URI: "https://keycloak.localssl.dev/realms/master/login-actions/reset-credentials"
|
||||
PHOTOPRISM_USAGE_INFO: "true"
|
||||
PHOTOPRISM_FILES_QUOTA: "100"
|
||||
## Customization:
|
||||
PHOTOPRISM_DEFAULT_LOCALE: "en" # default user interface language, e.g. "en" or "de"
|
||||
PHOTOPRISM_PLACES_LOCALE: "local" # location details language, e.g. "local", "en", or "de"
|
||||
## OpenID Connect (pre-configured for local tests):
|
||||
## see https://keycloak.localssl.dev/realms/master/.well-known/openid-configuration
|
||||
PHOTOPRISM_OIDC_URI: "https://keycloak.localssl.dev/realms/master"
|
||||
@@ -113,26 +119,29 @@ services:
|
||||
PHOTOPRISM_RAW_PRESETS: "false" # enables applying user presets when converting RAW images (reduces performance)
|
||||
PHOTOPRISM_DETECT_NSFW: "false" # automatically flags photos as private that MAY be offensive (requires TensorFlow)
|
||||
PHOTOPRISM_UPLOAD_NSFW: "false" # allows uploads that MAY be offensive (no effect without TensorFlow)
|
||||
PHOTOPRISM_UPLOAD_ALLOW: "" # restricts uploads to these file types (comma-separated list of EXTENSIONS; leave blank to allow all)
|
||||
PHOTOPRISM_UPLOAD_ARCHIVES: "true" # allows upload of zip archives (will be extracted before import)
|
||||
PHOTOPRISM_THUMB_LIBRARY: "auto" # image processing library to be used for generating thumbnails (auto, imaging, vips)
|
||||
PHOTOPRISM_THUMB_FILTER: "auto" # downscaling filter (imaging best to worst: blackman, lanczos, cubic, linear, nearest)
|
||||
PHOTOPRISM_THUMB_UNCACHED: "true" # enables on-demand thumbnail rendering (high memory and cpu usage)
|
||||
TF_CPP_MIN_LOG_LEVEL: 0 # show TensorFlow log messages for development
|
||||
## Video Transcoding (https://docs.photoprism.app/getting-started/advanced/transcoding/):
|
||||
# PHOTOPRISM_FFMPEG_ENCODER: "software" # H.264/AVC encoder (software, intel, nvidia, apple, raspberry, or vaapi)
|
||||
# PHOTOPRISM_FFMPEG_SIZE: "1920" # video size limit in pixels (720-7680) (default: 3840)
|
||||
# PHOTOPRISM_FFMPEG_BITRATE: "32" # video bitrate limit in Mbit/s (default: 50)
|
||||
# LIBVA_DRIVER_NAME: "i965" # For Intel architectures Haswell and older which do not support QSV yet but use VAAPI instead
|
||||
## Run/install on first startup (options: update https gpu ffmpeg tensorflow davfs clitools clean):
|
||||
PHOTOPRISM_INIT: "https tensorflow"
|
||||
## Share hardware devices with FFmpeg and TensorFlow (optional):
|
||||
PHOTOPRISM_FFMPEG_SIZE: "1920" # video size limit in pixels (720-7680) (default: 3840)
|
||||
# PHOTOPRISM_FFMPEG_BITRATE: "64" # video bitrate limit in Mbps (default: 60)
|
||||
## Run/install on first startup (options: update tensorflow https intel gpu davfs yt-dlp):
|
||||
PHOTOPRISM_INIT: "https"
|
||||
## Computer Vision API (https://docs.photoprism.app/getting-started/config-options/#computer-vision):
|
||||
PHOTOPRISM_VISION_API: "true" # server: enables service API endpoints under /api/v1/vision (requires access token)
|
||||
PHOTOPRISM_VISION_URI: "" # client: service URI, e.g. http://hostname/api/v1/vision (leave blank to disable)
|
||||
PHOTOPRISM_VISION_KEY: "" # client: service access token (for authentication)
|
||||
## External dependencies and tools:
|
||||
TF_CPP_MIN_LOG_LEVEL: 1
|
||||
GOCACHE: "/go/src/github.com/photoprism/photoprism/.local/gocache"
|
||||
CODEX_HOME: "/go/src/github.com/photoprism/photoprism/.local/codex"
|
||||
## Shared devices for video hardware transcoding (optional):
|
||||
# devices:
|
||||
# - "/dev/dri:/dev/dri" # Intel QSV (Broadwell and later) or VAAPI (Haswell and earlier)
|
||||
# - "/dev/nvidia0:/dev/nvidia0" # Nvidia CUDA
|
||||
# - "/dev/nvidiactl:/dev/nvidiactl"
|
||||
# - "/dev/nvidia-modeset:/dev/nvidia-modeset"
|
||||
# - "/dev/nvidia-nvswitchctl:/dev/nvidia-nvswitchctl"
|
||||
# - "/dev/nvidia-uvm:/dev/nvidia-uvm"
|
||||
# - "/dev/nvidia-uvm-tools:/dev/nvidia-uvm-tools"
|
||||
# - "/dev/dri:/dev/dri" # Required Intel QSV or VAAPI hardware transcoding
|
||||
# - "/dev/video11:/dev/video11" # Video4Linux Video Encode Device (h264_v4l2m2m)
|
||||
working_dir: "/go/src/github.com/photoprism/photoprism"
|
||||
volumes:
|
||||
@@ -164,6 +173,150 @@ services:
|
||||
MARIADB_PASSWORD: "photoprism"
|
||||
MARIADB_ROOT_PASSWORD: "photoprism"
|
||||
|
||||
## Qdrant (Vector Database)
|
||||
## Docs: https://qdrant.tech/documentation/guides/installation/#docker-compose
|
||||
## Release Notes: https://github.com/qdrant/qdrant/releases
|
||||
## Web UI: https://qdrant.localssl.dev/dashboard
|
||||
qdrant:
|
||||
image: qdrant/qdrant:latest
|
||||
profiles: [ "all", "qdrant" ]
|
||||
links:
|
||||
- "traefik:localssl.dev"
|
||||
- "traefik:app.localssl.dev"
|
||||
- "traefik:vision.localssl.dev"
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.services.qdrant.loadbalancer.server.port=6333"
|
||||
- "traefik.http.services.qdrant.loadbalancer.server.scheme=http"
|
||||
- "traefik.http.routers.qdrant.entrypoints=websecure"
|
||||
- "traefik.http.routers.qdrant.rule=Host(`qdrant.localssl.dev`)"
|
||||
- "traefik.http.routers.qdrant.priority=3"
|
||||
- "traefik.http.routers.qdrant.tls.domains[0].main=localssl.dev"
|
||||
- "traefik.http.routers.qdrant.tls.domains[0].sans=*.localssl.dev"
|
||||
- "traefik.http.routers.qdrant.tls=true"
|
||||
expose:
|
||||
- 6333
|
||||
- 6334
|
||||
- 6335
|
||||
volumes:
|
||||
- "./.qdrant.yaml:/qdrant/config/production.yaml"
|
||||
- "./storage/services/qdrant:/qdrant/storage"
|
||||
|
||||
## Ollama Large-Language Model Runner
|
||||
## run "ollama pull [name]:[version]" to download a vision model
|
||||
## listed at <https://ollama.com/search?c=vision>, for example:
|
||||
## docker compose exec ollama ollama pull gemma3:latest
|
||||
ollama:
|
||||
image: ollama/ollama:latest
|
||||
restart: unless-stopped
|
||||
stop_grace_period: 10s
|
||||
## Only starts this service if the "all", "ollama", or "vision" profile is specified::
|
||||
## docker compose --profile ollama up -d
|
||||
profiles: [ "all", "ollama", "vision" ]
|
||||
## Insecurely exposes the Ollama service on port 11434
|
||||
## without authentication (for private networks only):
|
||||
# ports:
|
||||
# - "11434:11434"
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=photoprism"
|
||||
- "traefik.http.services.ollama.loadbalancer.server.port=11434"
|
||||
- "traefik.http.routers.ollama.rule=Host(`ollama.localssl.dev`)"
|
||||
- "traefik.http.routers.ollama.entrypoints=websecure"
|
||||
- "traefik.http.routers.ollama.tls=true"
|
||||
environment:
|
||||
## Ollama Configuration Options:
|
||||
OLLAMA_HOST: "0.0.0.0:11434"
|
||||
OLLAMA_MODELS: "/root/.ollama" # model storage path (see volumes section below)
|
||||
OLLAMA_MAX_QUEUE: "100" # maximum number of queued requests
|
||||
OLLAMA_NUM_PARALLEL: "1" # maximum number of parallel requests
|
||||
OLLAMA_MAX_LOADED_MODELS: "1" # maximum number of loaded models per GPU
|
||||
OLLAMA_LOAD_TIMEOUT: "5m" # maximum time for loading models (default "5m")
|
||||
OLLAMA_KEEP_ALIVE: "5m" # duration that models stay loaded in memory (default "5m")
|
||||
OLLAMA_CONTEXT_LENGTH: "4096" # maximum input context length
|
||||
OLLAMA_MULTIUSER_CACHE: "false" # optimize prompt caching for multi-user scenarios
|
||||
OLLAMA_NOPRUNE: "false" # disables pruning of model blobs at startup
|
||||
OLLAMA_NOHISTORY: "true" # disables readline history
|
||||
OLLAMA_FLASH_ATTENTION: "false" # enables the experimental flash attention feature
|
||||
OLLAMA_KV_CACHE_TYPE: "f16" # cache quantization (f16, q8_0, or q4_0)
|
||||
OLLAMA_SCHED_SPREAD: "false" # allows scheduling models across all GPUs.
|
||||
OLLAMA_NEW_ENGINE: "true" # enables the new Ollama engine
|
||||
# OLLAMA_DEBUG: "true" # shows additional debug information
|
||||
# OLLAMA_INTEL_GPU: "true" # enables experimental Intel GPU detection
|
||||
## NVIDIA GPU Hardware Acceleration (optional):
|
||||
# NVIDIA_VISIBLE_DEVICES: "all"
|
||||
# NVIDIA_DRIVER_CAPABILITIES: "compute,utility"
|
||||
volumes:
|
||||
- "./storage/services/ollama:/root/.ollama"
|
||||
## NVIDIA GPU Hardware Acceleration (optional):
|
||||
# deploy:
|
||||
# resources:
|
||||
# reservations:
|
||||
# devices:
|
||||
# - driver: "nvidia"
|
||||
# capabilities: [ gpu ]
|
||||
# count: "all"
|
||||
|
||||
## Open WebUI, a Web Interface for Ollama
|
||||
## see https://github.com/open-webui/open-webui
|
||||
open-webui:
|
||||
image: ghcr.io/open-webui/open-webui:main
|
||||
restart: unless-stopped
|
||||
stop_grace_period: 5s
|
||||
## Only starts this service if the "all", "ollama", "open-webui", or "vision" profile is specified::
|
||||
## docker compose --profile ollama up -d
|
||||
profiles: [ "all", "ollama", "open-webui", "vision" ]
|
||||
## Exposes Open WebUI at http://localhost:8080 (use https://chat.localssl.dev/ to access it through Traefik):
|
||||
ports:
|
||||
- "127.0.0.1:8080:8080"
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=photoprism"
|
||||
- "traefik.http.services.open-webui.loadbalancer.server.port=8080"
|
||||
- "traefik.http.routers.open-webui.rule=Host(`chat.localssl.dev`) || Host(`open-webui.localssl.dev`) || Host(`ollama-ui.localssl.dev`)"
|
||||
- "traefik.http.routers.open-webui.entrypoints=websecure"
|
||||
- "traefik.http.routers.open-webui.tls=true"
|
||||
environment:
|
||||
WEBUI_URL: "https://chat.localssl.dev"
|
||||
# WEBUI_SECRET_KEY: ""
|
||||
OLLAMA_BASE_URL: "http://ollama:11434"
|
||||
ANONYMIZED_TELEMETRY: "false" # disable Chroma telemetry
|
||||
HF_HUB_DISABLE_TELEMETRY: "1" # disable Hugging Face telemetry
|
||||
# HUGGING_FACE_HUB_TOKEN: "" # see https://huggingface.co/docs/hub/en/security-tokens
|
||||
volumes:
|
||||
- "./storage/services/open-webui:/app/backend/data"
|
||||
|
||||
## PhotoPrism® Computer Vision API
|
||||
## see https://github.com/photoprism/photoprism-vision
|
||||
photoprism-vision:
|
||||
image: photoprism/vision:latest
|
||||
## Only starts this service if the "all" or "vision" profile is specified::
|
||||
## docker compose --profile vision up -d
|
||||
profiles: [ "all", "vision" ]
|
||||
stop_grace_period: 15s
|
||||
working_dir: "/app"
|
||||
links:
|
||||
- "traefik:localssl.dev"
|
||||
- "traefik:app.localssl.dev"
|
||||
- "traefik:qdrant.localssl.dev"
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.services.qdrant.loadbalancer.server.port=5000"
|
||||
- "traefik.http.services.qdrant.loadbalancer.server.scheme=http"
|
||||
- "traefik.http.routers.qdrant.entrypoints=websecure"
|
||||
- "traefik.http.routers.qdrant.rule=Host(`vision.localssl.dev`)"
|
||||
- "traefik.http.routers.qdrant.priority=3"
|
||||
- "traefik.http.routers.qdrant.tls.domains[0].main=localssl.dev"
|
||||
- "traefik.http.routers.qdrant.tls.domains[0].sans=*.localssl.dev"
|
||||
- "traefik.http.routers.qdrant.tls=true"
|
||||
expose:
|
||||
- 5000
|
||||
environment:
|
||||
TF_CPP_MIN_LOG_LEVEL: 2
|
||||
## Ollama client configuration (for the service, see below):
|
||||
OLLAMA_ENABLED: "true"
|
||||
OLLAMA_HOST: "http://ollama:11434"
|
||||
|
||||
## Traefik v3 (Reverse Proxy)
|
||||
## includes "*.localssl.dev" SSL certificate for test environments
|
||||
## Docs: https://doc.traefik.io/traefik/
|
||||
@@ -262,7 +415,7 @@ services:
|
||||
## ./photoprism client add --id=cs5cpu17n6gj2qo5 --secret=xcCbOrw6I0vcoXzhnOmXhjpVSyFq0l0e -s metrics -n Prometheus -e 60 -t 1
|
||||
prometheus:
|
||||
image: prom/prometheus:latest
|
||||
profiles: ["all", "auth", "prometheus"]
|
||||
profiles: [ "all", "auth", "prometheus" ]
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.services.prometheus.loadbalancer.server.port=9090"
|
||||
@@ -282,7 +435,7 @@ volumes:
|
||||
mariadb:
|
||||
driver: local
|
||||
|
||||
## Create shared "photoprism-develop" network for connecting with services in other compose.yaml files
|
||||
## Create shared "photoprism" network for connecting with services in other compose.yaml files
|
||||
networks:
|
||||
default:
|
||||
name: photoprism
|
||||
|
@@ -1,8 +1,9 @@
|
||||
FROM photoprism/photoprism:preview-ce AS build
|
||||
|
||||
# Set environment variables
|
||||
ENV TF_CPP_MIN_LOG_LEVEL=2 \
|
||||
MALLOC_ARENA_MAX="4" \
|
||||
ENV TF_CPP_MIN_LOG_LEVEL=4 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
PHOTOPRISM_STORAGE_PATH="/photoprism/storage" \
|
||||
PHOTOPRISM_DEBUG="false" \
|
||||
PHOTOPRISM_READONLY="false" \
|
||||
|
@@ -1,7 +1,6 @@
|
||||
services:
|
||||
demo:
|
||||
restart: always
|
||||
command: photoprism --public start
|
||||
image: photoprism/demo:latest
|
||||
container_name: demo
|
||||
depends_on:
|
||||
@@ -14,6 +13,8 @@ services:
|
||||
volumes:
|
||||
- "./config:/photoprism/storage/config"
|
||||
environment:
|
||||
PHOTOPRISM_DEMO: "true"
|
||||
PHOTOPRISM_PUBLIC: "true"
|
||||
PHOTOPRISM_SITE_URL: "https://demo.yourdomain.com/"
|
||||
# PHOTOPRISM_CDN_URL: "https://demo-cdn.yourdomain.com/"
|
||||
PHOTOPRISM_SITE_TITLE: "PhotoPrism"
|
||||
@@ -26,7 +27,7 @@ services:
|
||||
|
||||
traefik:
|
||||
restart: always
|
||||
image: traefik:v3.1
|
||||
image: traefik:v3.5
|
||||
container_name: traefik
|
||||
ports:
|
||||
- "80:80"
|
||||
|
@@ -1,8 +1,9 @@
|
||||
FROM photoprism/photoprism:preview-ce-debian AS build
|
||||
|
||||
# Set environment variables
|
||||
ENV TF_CPP_MIN_LOG_LEVEL=2 \
|
||||
MALLOC_ARENA_MAX="4" \
|
||||
ENV TF_CPP_MIN_LOG_LEVEL=4 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
PHOTOPRISM_STORAGE_PATH="/photoprism/storage" \
|
||||
PHOTOPRISM_DEBUG="false" \
|
||||
PHOTOPRISM_READONLY="false" \
|
||||
|
@@ -6,7 +6,7 @@ serversTransport:
|
||||
# Required to proxy services with self-signed HTTPS certificates:
|
||||
insecureSkipVerify: true
|
||||
|
||||
# Open ports ond protocols (HTTP will be redirected to HTTPS):
|
||||
# Open ports and protocols (HTTP will be redirected to HTTPS):
|
||||
entryPoints:
|
||||
web:
|
||||
address: ":80"
|
||||
|
@@ -1,8 +1,9 @@
|
||||
FROM photoprism/photoprism:preview-ce-ubuntu AS build
|
||||
|
||||
# Set environment variables
|
||||
ENV TF_CPP_MIN_LOG_LEVEL=2 \
|
||||
MALLOC_ARENA_MAX="4" \
|
||||
ENV TF_CPP_MIN_LOG_LEVEL=4 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
PHOTOPRISM_STORAGE_PATH="/photoprism/storage" \
|
||||
PHOTOPRISM_DEBUG="false" \
|
||||
PHOTOPRISM_READONLY="false" \
|
||||
|
@@ -1,8 +1,9 @@
|
||||
FROM photoprism/photoprism:unstable-ce AS build
|
||||
|
||||
# Set environment variables
|
||||
ENV TF_CPP_MIN_LOG_LEVEL=2 \
|
||||
MALLOC_ARENA_MAX="4" \
|
||||
ENV TF_CPP_MIN_LOG_LEVEL=4 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
PHOTOPRISM_STORAGE_PATH="/photoprism/storage" \
|
||||
PHOTOPRISM_DEBUG="false" \
|
||||
PHOTOPRISM_READONLY="false" \
|
||||
|
@@ -30,14 +30,16 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
||||
NODE_ENV="production" \
|
||||
DEBIAN_FRONTEND="noninteractive" \
|
||||
TMPDIR="/tmp" \
|
||||
TF_CPP_MIN_LOG_LEVEL="0" \
|
||||
MALLOC_ARENA_MAX="4" \
|
||||
TF_VERSION=1.15.2 \
|
||||
TF_CPP_MIN_LOG_LEVEL=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
GOPATH="/go" \
|
||||
GOBIN="/usr/local/bin" \
|
||||
GO111MODULE="on" \
|
||||
CGO_CFLAGS="-g -O2 -Wno-return-local-addr" \
|
||||
PROG="photoprism" \
|
||||
S6_KEEP_ENV=1 \
|
||||
S6_VERBOSITY=0 \
|
||||
S6_LOGGING=0
|
||||
|
||||
# Copy scripts and package sources config.
|
||||
@@ -62,6 +64,7 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
|
||||
iputils-ping dnsutils \
|
||||
&& \
|
||||
/scripts/install-nodejs.sh && \
|
||||
/scripts/install-yt-dlp.sh && \
|
||||
/scripts/install-libheif.sh && \
|
||||
/scripts/install-tensorflow.sh && \
|
||||
echo "ALL ALL=(ALL) NOPASSWD:SETENV: ALL" >> /etc/sudoers.d/all && \
|
||||
|
@@ -29,8 +29,9 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
||||
LD_LIBRARY_PATH="/usr/local/lib:/usr/lib" \
|
||||
TMPDIR="/tmp" \
|
||||
DEBIAN_FRONTEND="noninteractive" \
|
||||
TF_CPP_MIN_LOG_LEVEL="2" \
|
||||
MALLOC_ARENA_MAX="4" \
|
||||
TF_CPP_MIN_LOG_LEVEL=4 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
PROG="photoprism"
|
||||
|
||||
# Copy scripts and package sources config.
|
||||
|
@@ -30,8 +30,9 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
||||
LD_LIBRARY_PATH="/usr/local/lib:/usr/lib" \
|
||||
DEBIAN_FRONTEND="noninteractive" \
|
||||
TMPDIR="/tmp" \
|
||||
TF_CPP_MIN_LOG_LEVEL="0" \
|
||||
MALLOC_ARENA_MAX="4" \
|
||||
TF_CPP_MIN_LOG_LEVEL=1 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
GOPATH="/go" \
|
||||
GOBIN="/usr/local/bin" \
|
||||
GO111MODULE="on" \
|
||||
|
@@ -29,8 +29,9 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
||||
LD_LIBRARY_PATH="/usr/local/lib:/usr/lib" \
|
||||
TMPDIR="/tmp" \
|
||||
DEBIAN_FRONTEND="noninteractive" \
|
||||
TF_CPP_MIN_LOG_LEVEL="2" \
|
||||
MALLOC_ARENA_MAX="4" \
|
||||
TF_CPP_MIN_LOG_LEVEL=4 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
PROG="photoprism"
|
||||
|
||||
# copy scripts and debian backports sources list
|
||||
|
@@ -30,8 +30,9 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
||||
LD_LIBRARY_PATH="/usr/local/lib:/usr/lib" \
|
||||
DEBIAN_FRONTEND="noninteractive" \
|
||||
TMPDIR="/tmp" \
|
||||
TF_CPP_MIN_LOG_LEVEL="0" \
|
||||
MALLOC_ARENA_MAX="4" \
|
||||
TF_CPP_MIN_LOG_LEVEL=1 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
GOPATH="/go" \
|
||||
GOBIN="/usr/local/bin" \
|
||||
GO111MODULE="on" \
|
||||
@@ -53,6 +54,7 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
|
||||
apt-get update && apt-get -qq dist-upgrade && \
|
||||
apt-get -qq install \
|
||||
apt-utils \
|
||||
ripgrep \
|
||||
gpg \
|
||||
pkg-config \
|
||||
software-properties-common \
|
||||
|
@@ -30,8 +30,9 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
||||
NODE_ENV="production" \
|
||||
DEBIAN_FRONTEND="noninteractive" \
|
||||
TMPDIR="/tmp" \
|
||||
TF_CPP_MIN_LOG_LEVEL="0" \
|
||||
MALLOC_ARENA_MAX="4" \
|
||||
TF_CPP_MIN_LOG_LEVEL=1 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
GOPATH="/go" \
|
||||
GOBIN="/usr/local/bin" \
|
||||
GO111MODULE="on" \
|
||||
@@ -52,6 +53,7 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
|
||||
echo 'force-confold' > /etc/dpkg/dpkg.cfg.d/force-confold && \
|
||||
apt-get update && apt-get -qq dist-upgrade && apt-get -qq install --no-install-recommends \
|
||||
apt-utils \
|
||||
ripgrep \
|
||||
gpg \
|
||||
pkg-config \
|
||||
software-properties-common \
|
||||
|
@@ -30,8 +30,9 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
||||
NODE_ENV="production" \
|
||||
DEBIAN_FRONTEND="noninteractive" \
|
||||
TMPDIR="/tmp" \
|
||||
TF_CPP_MIN_LOG_LEVEL="0" \
|
||||
MALLOC_ARENA_MAX="4" \
|
||||
TF_CPP_MIN_LOG_LEVEL=1 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
GOPATH="/go" \
|
||||
GOBIN="/usr/local/bin" \
|
||||
GO111MODULE="on" \
|
||||
@@ -51,6 +52,7 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
|
||||
echo 'force-confold' > /etc/dpkg/dpkg.cfg.d/force-confold && \
|
||||
apt-get update && apt-get -qq dist-upgrade && apt-get -qq install --no-install-recommends \
|
||||
apt-utils \
|
||||
ripgrep \
|
||||
gpg \
|
||||
gpg-agent \
|
||||
pkg-config \
|
||||
|
@@ -29,10 +29,12 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
||||
LD_LIBRARY_PATH="/usr/local/lib:/usr/lib" \
|
||||
TMPDIR="/tmp" \
|
||||
DEBIAN_FRONTEND="noninteractive" \
|
||||
TF_CPP_MIN_LOG_LEVEL="2" \
|
||||
MALLOC_ARENA_MAX="4" \
|
||||
TF_CPP_MIN_LOG_LEVEL=4 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
PROG="photoprism" \
|
||||
S6_KEEP_ENV=1 \
|
||||
S6_KEEP_ENV=0 \
|
||||
S6_VERBOSITY=0 \
|
||||
S6_LOGGING=0
|
||||
|
||||
# Copy scripts and package sources config.
|
||||
@@ -48,13 +50,14 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
|
||||
apt-get update && apt-get -qq dist-upgrade && \
|
||||
apt-get -qq install \
|
||||
libc6 ca-certificates bash sudo nano avahi-utils jq lsof lshw \
|
||||
xz-utils exiftool sqlite3 tzdata gpg make zip unzip wget curl rsync \
|
||||
xz-utils exiftool sqlite3 postgresql-client tzdata gpg make zip unzip wget curl rsync \
|
||||
imagemagick libvips-dev rawtherapee ffmpeg libavcodec-extra x264 x265 libde265-dev \
|
||||
libaom-dev libvpx-dev libwebm-dev libjpeg-dev libmatroska-dev libdvdread-dev libebml5 libgav1-bin libatomic1 \
|
||||
iputils-ping dnsutils \
|
||||
va-driver-all libva2 iputils-ping dnsutils libmagic-mgc \
|
||||
&& \
|
||||
/scripts/install-mariadb.sh mariadb-client && \
|
||||
/scripts/install-darktable.sh && \
|
||||
/scripts/install-yt-dlp.sh && \
|
||||
/scripts/install-libheif.sh && \
|
||||
echo 'alias ll="ls -alh"' >> /etc/skel/.bashrc && \
|
||||
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
|
||||
@@ -72,6 +75,8 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
|
||||
/photoprism/storage/config \
|
||||
/photoprism/storage/cache && \
|
||||
/scripts/install-s6.sh && \
|
||||
ln -sf /scripts/services/photoprism /etc/s6-overlay/s6-rc.d/photoprism && \
|
||||
touch /etc/s6-overlay/s6-rc.d/user/contents.d/photoprism && \
|
||||
/scripts/cleanup.sh
|
||||
|
||||
# Set default working directory.
|
||||
@@ -82,4 +87,3 @@ EXPOSE 2342 2442 2443
|
||||
|
||||
# Set default entrypoint and command.
|
||||
ENTRYPOINT ["/init"]
|
||||
CMD ["/scripts/cmd.sh", "tail", "-f", "/dev/null"]
|
@@ -30,14 +30,16 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
||||
LD_LIBRARY_PATH="/usr/local/lib:/usr/lib" \
|
||||
DEBIAN_FRONTEND="noninteractive" \
|
||||
TMPDIR="/tmp" \
|
||||
TF_CPP_MIN_LOG_LEVEL="0" \
|
||||
MALLOC_ARENA_MAX="4" \
|
||||
TF_CPP_MIN_LOG_LEVEL=1 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
GOPATH="/go" \
|
||||
GOBIN="/usr/local/bin" \
|
||||
GO111MODULE="on" \
|
||||
CGO_CFLAGS="-g -O2 -Wno-return-local-addr" \
|
||||
PROG="photoprism" \
|
||||
S6_KEEP_ENV=1 \
|
||||
S6_VERBOSITY=0 \
|
||||
S6_LOGGING=0
|
||||
|
||||
# Copy scripts and package sources config.
|
||||
@@ -54,24 +56,28 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
|
||||
apt-get update && apt-get -qq dist-upgrade && \
|
||||
apt-get -qq install \
|
||||
libc6 ca-certificates bash sudo nano avahi-utils jq lsof lshw \
|
||||
xz-utils exiftool sqlite3 tzdata gpg make zip unzip wget curl rsync \
|
||||
xz-utils exiftool sqlite3 postgresql-client tzdata gpg make zip unzip wget curl rsync \
|
||||
imagemagick libvips-dev rawtherapee ffmpeg libavcodec-extra x264 x265 libde265-dev \
|
||||
libaom-dev libvpx-dev libwebm-dev libjpeg-dev libmatroska-dev libdvdread-dev libebml5 libgav1-bin libatomic1 \
|
||||
iputils-ping dnsutils \
|
||||
va-driver-all libva2 iputils-ping dnsutils libmagic-mgc \
|
||||
&& \
|
||||
apt-get -qq install \
|
||||
apt-utils pkg-config software-properties-common \
|
||||
build-essential gcc g++ git gettext davfs2 chrpath apache2-utils \
|
||||
autoconf automake cmake libtool libjpeg-dev libpng-dev libwebp-dev libavcodec-dev \
|
||||
build-essential software-properties-common pkg-config apt-utils \
|
||||
gcc g++ git autoconf automake cmake gettext apache2-utils davfs2 \
|
||||
chrpath tree ripgrep fd-find bat shellcheck shfmt fzf \
|
||||
libtool libjpeg-dev libpng-dev libwebp-dev libavcodec-dev \
|
||||
libx264-dev libx265-dev libaom-dev libvpx-dev libwebm-dev libxft-dev \
|
||||
libc6-dev libhdf5-serial-dev libzmq3-dev libssl-dev libnss3 \
|
||||
libfreetype6 libfreetype6-dev libfontconfig1 libfontconfig1-dev fonts-roboto \
|
||||
librsvg2-bin ghostscript gsfonts pdf2svg ps2eps \
|
||||
&& \
|
||||
ln -sf /usr/bin/fdfind /usr/local/bin/fd && \
|
||||
ln -sf /usr/bin/batcat /usr/local/bin/bat && \
|
||||
/scripts/install-nodejs.sh && \
|
||||
/scripts/install-mariadb.sh mariadb-client && \
|
||||
/scripts/install-tensorflow.sh && \
|
||||
/scripts/install-darktable.sh && \
|
||||
/scripts/install-yt-dlp.sh && \
|
||||
/scripts/install-libheif.sh && \
|
||||
/scripts/install-chrome.sh && \
|
||||
echo "ALL ALL=(ALL) NOPASSWD:SETENV: ALL" >> /etc/sudoers.d/all && \
|
||||
|
@@ -29,8 +29,9 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
||||
LD_LIBRARY_PATH="/usr/local/lib:/usr/lib" \
|
||||
TMPDIR="/tmp" \
|
||||
DEBIAN_FRONTEND="noninteractive" \
|
||||
TF_CPP_MIN_LOG_LEVEL="2" \
|
||||
MALLOC_ARENA_MAX="4" \
|
||||
TF_CPP_MIN_LOG_LEVEL=4 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
PROG="photoprism"
|
||||
|
||||
# Copy scripts and package sources config.
|
||||
|
@@ -30,8 +30,9 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
||||
LD_LIBRARY_PATH="/usr/local/lib:/usr/lib" \
|
||||
DEBIAN_FRONTEND="noninteractive" \
|
||||
TMPDIR="/tmp" \
|
||||
TF_CPP_MIN_LOG_LEVEL="0" \
|
||||
MALLOC_ARENA_MAX="4" \
|
||||
TF_CPP_MIN_LOG_LEVEL=1 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
GOPATH="/go" \
|
||||
GOBIN="/usr/local/bin" \
|
||||
GO111MODULE="on" \
|
||||
@@ -57,7 +58,7 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
|
||||
x264 x265 libde265-dev libaom-dev libvpx-dev libwebm-dev libjpeg-dev libmatroska-dev libdvdread-dev \
|
||||
&& \
|
||||
apt-get -qq install \
|
||||
apt-utils pkg-config software-properties-common \
|
||||
software-properties-common pkg-config apt-utils ripgrep fd-find bat eza \
|
||||
build-essential gcc g++ git gettext davfs2 chrpath apache2-utils \
|
||||
autoconf automake cmake libtool libjpeg-dev libpng-dev libwebp-dev \
|
||||
libx264-dev libx265-dev libaom-dev libvpx-dev libwebm-dev libxft-dev \
|
||||
@@ -65,6 +66,8 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
|
||||
libfreetype6 libfreetype6-dev libfontconfig1 libfontconfig1-dev fonts-roboto \
|
||||
librsvg2-bin ghostscript gsfonts pdf2svg ps2eps \
|
||||
&& \
|
||||
ln -sf /usr/bin/fdfind /usr/local/bin/fd && \
|
||||
ln -sf /usr/bin/batcat /usr/local/bin/bat && \
|
||||
/scripts/install-nodejs.sh && \
|
||||
/scripts/install-mariadb.sh mariadb-client && \
|
||||
/scripts/install-tensorflow.sh && \
|
||||
|
@@ -29,8 +29,9 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
||||
LD_LIBRARY_PATH="/usr/local/lib:/usr/lib" \
|
||||
TMPDIR="/tmp" \
|
||||
DEBIAN_FRONTEND="noninteractive" \
|
||||
TF_CPP_MIN_LOG_LEVEL="2" \
|
||||
MALLOC_ARENA_MAX="4" \
|
||||
TF_CPP_MIN_LOG_LEVEL=4 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
PROG="photoprism"
|
||||
|
||||
# Copy scripts and package sources config.
|
||||
|
@@ -30,8 +30,9 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
||||
LD_LIBRARY_PATH="/usr/local/lib:/usr/lib" \
|
||||
DEBIAN_FRONTEND="noninteractive" \
|
||||
TMPDIR="/tmp" \
|
||||
TF_CPP_MIN_LOG_LEVEL="0" \
|
||||
MALLOC_ARENA_MAX="4" \
|
||||
TF_CPP_MIN_LOG_LEVEL=1 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
GOPATH="/go" \
|
||||
GOBIN="/usr/local/bin" \
|
||||
GO111MODULE="on" \
|
||||
@@ -57,7 +58,7 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
|
||||
x264 x265 libde265-dev libaom-dev libvpx-dev libwebm-dev libjpeg-dev libmatroska-dev libdvdread-dev \
|
||||
&& \
|
||||
apt-get -qq install \
|
||||
apt-utils pkg-config software-properties-common \
|
||||
software-properties-common pkg-config apt-utils ripgrep fd-find bat eza \
|
||||
build-essential gcc g++ git gettext davfs2 chrpath apache2-utils \
|
||||
autoconf automake cmake libtool libjpeg-dev libpng-dev libwebp-dev \
|
||||
libx264-dev libx265-dev libaom-dev libvpx-dev libwebm-dev libxft-dev \
|
||||
@@ -65,6 +66,8 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
|
||||
libfreetype6 libfreetype6-dev libfontconfig1 libfontconfig1-dev fonts-roboto \
|
||||
librsvg2-bin ghostscript gsfonts pdf2svg ps2eps \
|
||||
&& \
|
||||
ln -sf /usr/bin/fdfind /usr/local/bin/fd && \
|
||||
ln -sf /usr/bin/batcat /usr/local/bin/bat && \
|
||||
/scripts/install-nodejs.sh && \
|
||||
/scripts/install-mariadb.sh mariadb-client && \
|
||||
/scripts/install-tensorflow.sh && \
|
||||
|
@@ -29,8 +29,9 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
||||
LD_LIBRARY_PATH="/usr/local/lib:/usr/lib" \
|
||||
TMPDIR="/tmp" \
|
||||
DEBIAN_FRONTEND="noninteractive" \
|
||||
TF_CPP_MIN_LOG_LEVEL="2" \
|
||||
MALLOC_ARENA_MAX="4" \
|
||||
TF_CPP_MIN_LOG_LEVEL=4 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
PROG="photoprism"
|
||||
|
||||
# Copy scripts and package sources config.
|
||||
@@ -46,7 +47,7 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
|
||||
apt-get update && apt-get -qq dist-upgrade && \
|
||||
apt-get -qq install \
|
||||
libc6 ca-certificates bash sudo nano tzdata gpg make zip unzip wget curl rsync \
|
||||
xz-utils avahi-utils jq lsof lshw libebml5 libgav1-bin libatomic1 exiftool sqlite3 \
|
||||
xz-utils avahi-utils jq lsof lshw libebml5 libgav1-bin libatomic1 exiftool sqlite3 postgresql-client \
|
||||
ffmpeg imagemagick libvips-dev rawtherapee libjxl-dev libjxl-tools libffmpeg-nvenc-dev librav1e-dev \
|
||||
libswscale-dev libavfilter-extra libavformat-extra libavcodec-extra x264 x265 libde265-dev libaom-dev \
|
||||
libvpx-dev libwebm-dev libjpeg-dev libmatroska-dev libdvdread-dev libdav1d-dev libsharpyuv0 \
|
||||
|
@@ -30,8 +30,9 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
||||
LD_LIBRARY_PATH="/usr/local/lib:/usr/lib" \
|
||||
DEBIAN_FRONTEND="noninteractive" \
|
||||
TMPDIR="/tmp" \
|
||||
TF_CPP_MIN_LOG_LEVEL="0" \
|
||||
MALLOC_ARENA_MAX="4" \
|
||||
TF_CPP_MIN_LOG_LEVEL=1 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
GOPATH="/go" \
|
||||
GOBIN="/usr/local/bin" \
|
||||
GO111MODULE="on" \
|
||||
@@ -52,14 +53,14 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
|
||||
apt-get update && apt-get -qq dist-upgrade && \
|
||||
apt-get -qq install \
|
||||
libc6 libbsd-dev ca-certificates bash sudo nano tzdata gpg make zip unzip wget curl rsync \
|
||||
xz-utils avahi-utils jq lsof lshw libebml5 libgav1-bin libatomic1 exiftool sqlite3 \
|
||||
xz-utils avahi-utils jq lsof lshw libebml5 libgav1-bin libatomic1 exiftool sqlite3 postgresql-client \
|
||||
ffmpeg imagemagick libvips-dev rawtherapee libjxl-dev libjxl-tools libffmpeg-nvenc-dev librav1e-dev \
|
||||
libswscale-dev libavfilter-extra libavformat-extra libavcodec-extra x264 x265 libde265-dev libaom-dev \
|
||||
libvpx-dev libwebm-dev libjpeg-dev libmatroska-dev libdvdread-dev libdav1d-dev libsharpyuv0 \
|
||||
iputils-ping dnsutils \
|
||||
&& \
|
||||
apt-get -qq install \
|
||||
software-properties-common pkg-config apt-utils \
|
||||
software-properties-common pkg-config apt-utils ripgrep fd-find bat eza \
|
||||
build-essential gcc g++ git gettext davfs2 chrpath apache2-utils \
|
||||
autoconf automake cmake libtool libjpeg-dev libpng-dev libwebp-dev libavcodec-dev \
|
||||
libx264-dev libx265-dev libaom-dev libvpx-dev libwebm-dev libxft-dev \
|
||||
@@ -67,6 +68,8 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
|
||||
libfreetype6 libfreetype6-dev libfontconfig1 libfontconfig1-dev fonts-roboto \
|
||||
librsvg2-bin ghostscript gsfonts pdf2svg ps2eps libsharpyuv-dev \
|
||||
&& \
|
||||
ln -sf /usr/bin/fdfind /usr/local/bin/fd && \
|
||||
ln -sf /usr/bin/batcat /usr/local/bin/bat && \
|
||||
/scripts/install-nodejs.sh && \
|
||||
/scripts/install-mariadb.sh mariadb-client && \
|
||||
/scripts/install-tensorflow.sh && \
|
||||
|
@@ -29,10 +29,12 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
||||
LD_LIBRARY_PATH="/usr/local/lib:/usr/lib" \
|
||||
TMPDIR="/tmp" \
|
||||
DEBIAN_FRONTEND="noninteractive" \
|
||||
TF_CPP_MIN_LOG_LEVEL="2" \
|
||||
MALLOC_ARENA_MAX="4" \
|
||||
TF_CPP_MIN_LOG_LEVEL=4 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
PROG="photoprism" \
|
||||
S6_KEEP_ENV=1 \
|
||||
S6_KEEP_ENV=0 \
|
||||
S6_VERBOSITY=0 \
|
||||
S6_LOGGING=0
|
||||
|
||||
# Copy scripts and package sources config.
|
||||
@@ -48,7 +50,7 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
|
||||
apt-get update && apt-get -qq dist-upgrade && \
|
||||
apt-get -qq install \
|
||||
libc6 ca-certificates bash sudo nano tzdata gpg make zip unzip wget curl rsync \
|
||||
xz-utils avahi-utils jq lsof lshw libebml5 libgav1-bin libatomic1 exiftool sqlite3 \
|
||||
xz-utils avahi-utils jq lsof lshw libebml5 libgav1-bin libatomic1 exiftool sqlite3 postgresql-client \
|
||||
ffmpeg imagemagick libvips-dev rawtherapee libjxl-dev libjxl-tools libffmpeg-nvenc-dev librav1e-dev \
|
||||
libswscale-dev libavfilter-extra libavformat-extra libavcodec-extra x264 x265 libde265-dev libaom-dev \
|
||||
libvpx-dev libwebm-dev libjpeg-dev libmatroska-dev libdvdread-dev libdav1d-dev libsharpyuv0 \
|
||||
@@ -73,6 +75,8 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
|
||||
/photoprism/storage/config \
|
||||
/photoprism/storage/cache && \
|
||||
/scripts/install-s6.sh && \
|
||||
ln -sf /scripts/services/photoprism /etc/s6-overlay/s6-rc.d/photoprism && \
|
||||
touch /etc/s6-overlay/s6-rc.d/user/contents.d/photoprism && \
|
||||
/scripts/cleanup.sh
|
||||
|
||||
# Set default working directory.
|
||||
@@ -83,4 +87,3 @@ EXPOSE 2342 2442 2443
|
||||
|
||||
# Set default entrypoint and command.
|
||||
ENTRYPOINT ["/init"]
|
||||
CMD ["/scripts/cmd.sh", "tail", "-f", "/dev/null"]
|
||||
|
@@ -30,14 +30,16 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
||||
LD_LIBRARY_PATH="/usr/local/lib:/usr/lib" \
|
||||
DEBIAN_FRONTEND="noninteractive" \
|
||||
TMPDIR="/tmp" \
|
||||
TF_CPP_MIN_LOG_LEVEL="0" \
|
||||
MALLOC_ARENA_MAX="4" \
|
||||
TF_CPP_MIN_LOG_LEVEL=1 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
GOPATH="/go" \
|
||||
GOBIN="/usr/local/bin" \
|
||||
GO111MODULE="on" \
|
||||
CGO_CFLAGS="-g -O2 -Wno-return-local-addr" \
|
||||
PROG="photoprism" \
|
||||
S6_KEEP_ENV=1 \
|
||||
S6_VERBOSITY=0 \
|
||||
S6_LOGGING=0
|
||||
|
||||
# Copy scripts and package sources config.
|
||||
@@ -54,14 +56,14 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
|
||||
apt-get update && apt-get -qq dist-upgrade && \
|
||||
apt-get -qq install \
|
||||
libc6 libbsd-dev ca-certificates bash sudo nano tzdata gpg make zip unzip wget curl rsync \
|
||||
xz-utils avahi-utils jq lsof lshw libebml5 libgav1-bin libatomic1 exiftool sqlite3 \
|
||||
xz-utils avahi-utils jq lsof lshw libebml5 libgav1-bin libatomic1 exiftool sqlite3 postgresql-client \
|
||||
ffmpeg imagemagick libvips-dev rawtherapee libjxl-dev libjxl-tools libffmpeg-nvenc-dev librav1e-dev \
|
||||
libswscale-dev libavfilter-extra libavformat-extra libavcodec-extra x264 x265 libde265-dev libaom-dev \
|
||||
libvpx-dev libwebm-dev libjpeg-dev libmatroska-dev libdvdread-dev libdav1d-dev libsharpyuv0 \
|
||||
iputils-ping dnsutils \
|
||||
&& \
|
||||
apt-get -qq install \
|
||||
software-properties-common pkg-config apt-utils \
|
||||
software-properties-common pkg-config apt-utils ripgrep fd-find bat eza \
|
||||
build-essential gcc g++ git gettext davfs2 chrpath apache2-utils \
|
||||
autoconf automake cmake libtool libjpeg-dev libpng-dev libwebp-dev libavcodec-dev \
|
||||
libx264-dev libx265-dev libaom-dev libvpx-dev libwebm-dev libxft-dev \
|
||||
@@ -69,6 +71,8 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
|
||||
libfreetype6 libfreetype6-dev libfontconfig1 libfontconfig1-dev fonts-roboto \
|
||||
librsvg2-bin ghostscript gsfonts pdf2svg ps2eps libsharpyuv-dev \
|
||||
&& \
|
||||
ln -sf /usr/bin/fdfind /usr/local/bin/fd && \
|
||||
ln -sf /usr/bin/batcat /usr/local/bin/bat && \
|
||||
/scripts/install-nodejs.sh && \
|
||||
/scripts/install-mariadb.sh mariadb-client && \
|
||||
/scripts/install-tensorflow.sh && \
|
||||
|
91
docker/develop/plucky-slim/Dockerfile
Normal file
91
docker/develop/plucky-slim/Dockerfile
Normal file
@@ -0,0 +1,91 @@
|
||||
#### Base Image: Ubuntu 25.04 (Plucky Puffin)
|
||||
FROM ubuntu:plucky
|
||||
|
||||
# Copyright © 2018 - 2025 PhotoPrism UG. All rights reserved.
|
||||
#
|
||||
# Questions? Email us at hello@photoprism.app or visit our website to learn
|
||||
# more about our team, products and services: https://www.photoprism.app/
|
||||
|
||||
# Add Open Container Initiative (OCI) annotations.
|
||||
# See: https://github.com/opencontainers/image-spec/blob/main/annotations.md
|
||||
LABEL org.opencontainers.image.title="PhotoPrism® Base Image (Ubuntu 25.04)"
|
||||
LABEL org.opencontainers.image.description="Ubuntu 25.04 (Plucky Puffin)"
|
||||
LABEL org.opencontainers.image.url="https://hub.docker.com/repository/docker/photoprism/develop"
|
||||
LABEL org.opencontainers.image.source="https://github.com/photoprism/photoprism"
|
||||
LABEL org.opencontainers.image.documentation="https://docs.photoprism.app/developer-guide/setup/"
|
||||
LABEL org.opencontainers.image.authors="PhotoPrism UG <hello@photoprism.app>"
|
||||
LABEL org.opencontainers.image.vendor="PhotoPrism UG"
|
||||
|
||||
# Declare build parameters.
|
||||
ARG TARGETARCH
|
||||
ARG BUILD_TAG
|
||||
|
||||
# Set environment variables, see https://docs.photoprism.app/getting-started/config-options/.
|
||||
ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
||||
DOCKER_TAG=$BUILD_TAG \
|
||||
DOCKER_ENV="prod" \
|
||||
PS1="\u@$BUILD_TAG:\w\$ " \
|
||||
PATH="/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin:/scripts:/opt/photoprism/bin" \
|
||||
LD_LIBRARY_PATH="/usr/local/lib:/usr/lib" \
|
||||
TMPDIR="/tmp" \
|
||||
DEBIAN_FRONTEND="noninteractive" \
|
||||
TF_CPP_MIN_LOG_LEVEL=4 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
PROG="photoprism" \
|
||||
S6_KEEP_ENV=0 \
|
||||
S6_VERBOSITY=0 \
|
||||
S6_LOGGING=0
|
||||
|
||||
# Copy scripts and package sources config.
|
||||
COPY --chown=root:root --chmod=755 /scripts/dist/ /scripts/
|
||||
|
||||
# Update base image and add dependencies.
|
||||
RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
|
||||
echo 'APT::Install-Recommends "false";' > /etc/apt/apt.conf.d/80recommends && \
|
||||
echo 'APT::Install-Suggests "false";' > /etc/apt/apt.conf.d/80suggests && \
|
||||
echo 'APT::Get::Assume-Yes "true";' > /etc/apt/apt.conf.d/80forceyes && \
|
||||
echo 'APT::Get::Fix-Missing "true";' > /etc/apt/apt.conf.d/80fixmissing && \
|
||||
echo 'force-confold' > /etc/dpkg/dpkg.cfg.d/force-confold && \
|
||||
apt-get update && apt-get -qq dist-upgrade && \
|
||||
apt-get -qq install \
|
||||
libc6 ca-certificates bash sudo nano tzdata gpg make zip unzip wget curl rsync \
|
||||
xz-utils avahi-utils jq lsof lshw libebml5 libgav1-bin libatomic1 exiftool sqlite3 postgresql-client \
|
||||
ffmpeg imagemagick libvips-dev rawtherapee libjxl-dev libjxl-tools libffmpeg-nvenc-dev librav1e-dev \
|
||||
libswscale-dev libavfilter-extra libavformat-extra libavcodec-extra x264 x265 libde265-dev libaom-dev \
|
||||
libvpx-dev libwebm-dev libjpeg-dev libmatroska-dev libdvdread-dev libdav1d-dev libsharpyuv0 \
|
||||
va-driver-all libva2 iputils-ping dnsutils libmagic-mgc \
|
||||
&& \
|
||||
/scripts/install-mariadb.sh mariadb-client && \
|
||||
/scripts/install-darktable.sh && \
|
||||
/scripts/install-yt-dlp.sh && \
|
||||
/scripts/install-libheif.sh && \
|
||||
echo 'alias ll="ls -alh"' >> /etc/skel/.bashrc && \
|
||||
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
|
||||
echo "ALL ALL=(ALL) NOPASSWD:SETENV: /scripts/entrypoint-init.sh" >> /etc/sudoers.d/init && \
|
||||
/scripts/install-dircolors.sh && \
|
||||
cp /etc/skel/.bashrc /root/.bashrc && \
|
||||
/scripts/create-users.sh && \
|
||||
install -d -m 0777 -o 1000 -g 1000 \
|
||||
/photoprism/originals \
|
||||
/photoprism/import \
|
||||
/photoprism/storage \
|
||||
/photoprism/storage/sidecar \
|
||||
/photoprism/storage/albums \
|
||||
/photoprism/storage/backups \
|
||||
/photoprism/storage/config \
|
||||
/photoprism/storage/cache && \
|
||||
/scripts/install-s6.sh && \
|
||||
ln -sf /scripts/services/photoprism /etc/s6-overlay/s6-rc.d/photoprism && \
|
||||
touch /etc/s6-overlay/s6-rc.d/user/contents.d/photoprism && \
|
||||
apt modernize-sources && \
|
||||
/scripts/cleanup.sh
|
||||
|
||||
# Set default working directory.
|
||||
WORKDIR /photoprism
|
||||
|
||||
# Expose default HTTP and HTTPS ports.
|
||||
EXPOSE 2342 2442 2443
|
||||
|
||||
# Set default entrypoint and command.
|
||||
ENTRYPOINT ["/init"]
|
130
docker/develop/plucky/Dockerfile
Normal file
130
docker/develop/plucky/Dockerfile
Normal file
@@ -0,0 +1,130 @@
|
||||
#### Base Image: Ubuntu 25.04 (Plucky Puffin)
|
||||
FROM ubuntu:plucky
|
||||
|
||||
# Copyright © 2018 - 2025 PhotoPrism UG. All rights reserved.
|
||||
#
|
||||
# Questions? Email us at hello@photoprism.app or visit our website to learn
|
||||
# more about our team, products and services: https://www.photoprism.app/
|
||||
|
||||
# Add Open Container Initiative (OCI) annotations.
|
||||
# See: https://github.com/opencontainers/image-spec/blob/main/annotations.md
|
||||
LABEL org.opencontainers.image.title="PhotoPrism® Build Image (Ubuntu 25.04)"
|
||||
LABEL org.opencontainers.image.description="Ubuntu 25.04 (Plucky Puffin)"
|
||||
LABEL org.opencontainers.image.url="https://hub.docker.com/repository/docker/photoprism/develop"
|
||||
LABEL org.opencontainers.image.source="https://github.com/photoprism/photoprism"
|
||||
LABEL org.opencontainers.image.documentation="https://docs.photoprism.app/developer-guide/setup/"
|
||||
LABEL org.opencontainers.image.authors="PhotoPrism UG <hello@photoprism.app>"
|
||||
LABEL org.opencontainers.image.vendor="PhotoPrism UG"
|
||||
|
||||
# Declare build parameters.
|
||||
ARG TARGETARCH
|
||||
ARG BUILD_TAG
|
||||
|
||||
# Set environment variables, see https://docs.photoprism.app/getting-started/config-options/.
|
||||
ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
||||
DOCKER_TAG=$BUILD_TAG \
|
||||
DOCKER_ENV="develop" \
|
||||
NODE_ENV="production" \
|
||||
PS1="\u@$BUILD_TAG:\w\$ " \
|
||||
PATH="/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin:/scripts:/usr/local/go/bin:/go/bin:/opt/photoprism/bin" \
|
||||
LD_LIBRARY_PATH="/usr/local/lib:/usr/lib" \
|
||||
DEBIAN_FRONTEND="noninteractive" \
|
||||
TMPDIR="/tmp" \
|
||||
TF_CPP_MIN_LOG_LEVEL=1 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
GOPATH="/go" \
|
||||
GOBIN="/usr/local/bin" \
|
||||
GO111MODULE="on" \
|
||||
CGO_CFLAGS="-g -O2 -Wno-return-local-addr" \
|
||||
PROG="photoprism" \
|
||||
S6_KEEP_ENV=1 \
|
||||
S6_VERBOSITY=0 \
|
||||
S6_LOGGING=0
|
||||
|
||||
# Copy scripts and package sources config.
|
||||
COPY --chown=root:root --chmod=755 /scripts/dist/ /scripts/
|
||||
COPY --chown=root:root --chmod=644 /.my.cnf /etc/my.cnf
|
||||
|
||||
# Update base image and add dependencies.
|
||||
RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
|
||||
echo 'APT::Install-Recommends "false";' > /etc/apt/apt.conf.d/80recommends && \
|
||||
echo 'APT::Install-Suggests "false";' > /etc/apt/apt.conf.d/80suggests && \
|
||||
echo 'APT::Get::Assume-Yes "true";' > /etc/apt/apt.conf.d/80forceyes && \
|
||||
echo 'APT::Get::Fix-Missing "true";' > /etc/apt/apt.conf.d/80fixmissing && \
|
||||
echo 'force-confold' > /etc/dpkg/dpkg.cfg.d/force-confold && \
|
||||
apt-get update && apt-get -qq dist-upgrade && \
|
||||
apt-get -qq install \
|
||||
libc6 libbsd-dev ca-certificates bash sudo nano tzdata gpg make zip unzip wget curl rsync \
|
||||
xz-utils avahi-utils jq lsof lshw libebml5 libgav1-bin libatomic1 exiftool sqlite3 postgresql-client \
|
||||
ffmpeg imagemagick libvips-dev rawtherapee libjxl-dev libjxl-tools libffmpeg-nvenc-dev librav1e-dev \
|
||||
libswscale-dev libavfilter-extra libavformat-extra libavcodec-extra x264 x265 libde265-dev libaom-dev \
|
||||
libvpx-dev libwebm-dev libjpeg-dev libmatroska-dev libdvdread-dev libdav1d-dev libsharpyuv0 \
|
||||
va-driver-all libva2 iputils-ping dnsutils libmagic-mgc \
|
||||
&& \
|
||||
apt-get -qq install \
|
||||
build-essential software-properties-common pkg-config apt-utils \
|
||||
gcc g++ git autoconf automake cmake gettext apache2-utils davfs2 \
|
||||
chrpath tree ripgrep fd-find bat eza git-delta shellcheck shfmt fzf \
|
||||
libtool libjpeg-dev libpng-dev libwebp-dev libavcodec-dev \
|
||||
libx264-dev libx265-dev libaom-dev libvpx-dev libwebm-dev libxft-dev \
|
||||
libc6-dev libhdf5-serial-dev libzmq3-dev libssl-dev libnss3 \
|
||||
libfreetype6 libfreetype6-dev libfontconfig1 libfontconfig1-dev fonts-roboto \
|
||||
librsvg2-bin ghostscript gsfonts pdf2svg ps2eps libsharpyuv-dev \
|
||||
&& \
|
||||
ln -sf /usr/bin/fdfind /usr/local/bin/fd && \
|
||||
ln -sf /usr/bin/batcat /usr/local/bin/bat && \
|
||||
/scripts/install-nodejs.sh && \
|
||||
/scripts/install-mariadb.sh mariadb-client && \
|
||||
/scripts/install-tensorflow.sh && \
|
||||
/scripts/install-darktable.sh && \
|
||||
/scripts/install-yt-dlp.sh && \
|
||||
/scripts/install-libheif.sh && \
|
||||
/scripts/install-chrome.sh && \
|
||||
echo "ALL ALL=(ALL) NOPASSWD:SETENV: ALL" >> /etc/sudoers.d/all && \
|
||||
mkdir -p /etc/skel/.config/go/telemetry && \
|
||||
echo 'off 2025-01-03' > '/etc/skel/.config/go/telemetry/mode' && \
|
||||
cp -r /etc/skel/.config /root/.config && \
|
||||
/scripts/install-go.sh && \
|
||||
/scripts/install-go-tools.sh && \
|
||||
echo 'alias go=richgo ll="ls -alh"' >> /etc/skel/.bashrc && \
|
||||
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
|
||||
/scripts/install-dircolors.sh && \
|
||||
cp /etc/skel/.bashrc /root/.bashrc && \
|
||||
cp /scripts/convert/policy.xml /etc/ImageMagick-7/policy.xml && \
|
||||
/scripts/create-users.sh && \
|
||||
install -d -m 0777 -o 1000 -g 1000 \
|
||||
/photoprism/originals \
|
||||
/photoprism/import \
|
||||
/photoprism/storage \
|
||||
/photoprism/storage/sidecar \
|
||||
/photoprism/storage/albums \
|
||||
/photoprism/storage/backups \
|
||||
/photoprism/storage/config \
|
||||
/photoprism/storage/cache && \
|
||||
/scripts/install-s6.sh && \
|
||||
apt modernize-sources && \
|
||||
/scripts/cleanup.sh
|
||||
|
||||
# Download machine learning models and test data.
|
||||
RUN mkdir /tmp/photoprism && \
|
||||
wget "https://dl.photoprism.app/tensorflow/nsfw.zip?${BUILD_TAG}" -O /tmp/photoprism/nsfw.zip && \
|
||||
wget "https://dl.photoprism.app/tensorflow/nasnet.zip?${BUILD_TAG}" -O /tmp/photoprism/nasnet.zip && \
|
||||
wget "https://dl.photoprism.app/tensorflow/facenet.zip?${BUILD_TAG}" -O /tmp/photoprism/facenet.zip && \
|
||||
wget "https://dl.photoprism.app/qa/testdata.zip?${BUILD_TAG}" -O /tmp/photoprism/testdata.zip
|
||||
|
||||
# Set default working directory.
|
||||
WORKDIR "/go/src/github.com/photoprism/photoprism"
|
||||
|
||||
# Expose the following container ports:
|
||||
# - 2342 (HTTP)
|
||||
# - 2343 (Acceptance Tests)
|
||||
# - 2442 (HTTP)
|
||||
# - 2443 (HTTPS)
|
||||
# - 9515 (Chromedriver)
|
||||
# - 40000 (Go Debugger)
|
||||
EXPOSE 2342 2343 2442 2443 9515 40000
|
||||
|
||||
# Set default entrypoint and command.
|
||||
ENTRYPOINT ["/init"]
|
||||
CMD ["/scripts/cmd.sh", "tail", "-f", "/dev/null"]
|
@@ -46,8 +46,9 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
||||
LD_LIBRARY_PATH="/usr/local/lib:/usr/lib" \
|
||||
TMPDIR="/tmp" \
|
||||
DEBIAN_FRONTEND="noninteractive" \
|
||||
TF_CPP_MIN_LOG_LEVEL="2" \
|
||||
MALLOC_ARENA_MAX="4" \
|
||||
TF_VERSION=1.15.2 \
|
||||
TF_CPP_MIN_LOG_LEVEL=4 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
PROG="photoprism" \
|
||||
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
||||
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
||||
@@ -91,7 +92,8 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
||||
PHOTOPRISM_AUTO_INDEX="300" \
|
||||
PHOTOPRISM_AUTO_IMPORT="-1" \
|
||||
PHOTOPRISM_INIT="https" \
|
||||
S6_KEEP_ENV=1 \
|
||||
S6_KEEP_ENV=0 \
|
||||
S6_VERBOSITY=0 \
|
||||
S6_LOGGING=0
|
||||
|
||||
# Copy dist files, scripts, and debian backports sources list.
|
||||
@@ -114,6 +116,7 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
|
||||
libvpx-dev libwebm-dev libjpeg-dev libmatroska-dev libdvdread-dev libdav1d-dev libsharpyuv0 \
|
||||
iputils-ping dnsutils \
|
||||
&& \
|
||||
/scripts/install-yt-dlp.sh && \
|
||||
/scripts/install-libheif.sh && \
|
||||
echo 'alias ll="ls -alh"' >> /etc/skel/.bashrc && \
|
||||
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
|
||||
@@ -131,6 +134,8 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
|
||||
/photoprism/storage/config \
|
||||
/photoprism/storage/cache && \
|
||||
/scripts/install-s6.sh && \
|
||||
ln -sf /scripts/services/photoprism /etc/s6-overlay/s6-rc.d/photoprism && \
|
||||
touch /etc/s6-overlay/s6-rc.d/user/contents.d/photoprism && \
|
||||
/scripts/cleanup.sh
|
||||
|
||||
# Set default working directory.
|
||||
@@ -141,4 +146,3 @@ EXPOSE 2342 2443
|
||||
|
||||
# Set default entrypoint and command.
|
||||
ENTRYPOINT ["/init"]
|
||||
CMD ["/scripts/cmd.sh", "/opt/photoprism/bin/photoprism", "start"]
|
||||
|
@@ -41,8 +41,9 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
||||
DOCKER_ENV="prod" \
|
||||
TMPDIR="/tmp" \
|
||||
DEBIAN_FRONTEND="noninteractive" \
|
||||
TF_CPP_MIN_LOG_LEVEL="2" \
|
||||
MALLOC_ARENA_MAX="4" \
|
||||
TF_CPP_MIN_LOG_LEVEL=4 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
PROG="photoprism" \
|
||||
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
||||
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
||||
|
@@ -41,8 +41,9 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
||||
DOCKER_ENV="prod" \
|
||||
TMPDIR="/tmp" \
|
||||
DEBIAN_FRONTEND="noninteractive" \
|
||||
TF_CPP_MIN_LOG_LEVEL="2" \
|
||||
MALLOC_ARENA_MAX="4" \
|
||||
TF_CPP_MIN_LOG_LEVEL=4 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
PROG="photoprism" \
|
||||
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
||||
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
||||
|
@@ -44,8 +44,9 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
||||
LD_LIBRARY_PATH="/usr/local/lib:/usr/lib" \
|
||||
TMPDIR="/tmp" \
|
||||
DEBIAN_FRONTEND="noninteractive" \
|
||||
TF_CPP_MIN_LOG_LEVEL="2" \
|
||||
MALLOC_ARENA_MAX="4" \
|
||||
TF_CPP_MIN_LOG_LEVEL=4 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
PROG="photoprism" \
|
||||
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
||||
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
||||
|
@@ -44,8 +44,9 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
||||
LD_LIBRARY_PATH="/usr/local/lib:/usr/lib" \
|
||||
TMPDIR="/tmp" \
|
||||
DEBIAN_FRONTEND="noninteractive" \
|
||||
TF_CPP_MIN_LOG_LEVEL="2" \
|
||||
MALLOC_ARENA_MAX="4" \
|
||||
TF_CPP_MIN_LOG_LEVEL=4 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
PROG="photoprism" \
|
||||
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
||||
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
||||
|
@@ -42,8 +42,9 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
||||
DOCKER_ENV="prod" \
|
||||
TMPDIR="/tmp" \
|
||||
DEBIAN_FRONTEND="noninteractive" \
|
||||
TF_CPP_MIN_LOG_LEVEL="2" \
|
||||
MALLOC_ARENA_MAX="4" \
|
||||
TF_CPP_MIN_LOG_LEVEL=4 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
PROG="photoprism" \
|
||||
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
||||
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
||||
@@ -90,6 +91,7 @@ COPY --chown=root:root --chmod=755 /scripts/dist/ /scripts/
|
||||
# Update pre-installed packages.
|
||||
RUN apt-get update && \
|
||||
apt-get -qq dist-upgrade && \
|
||||
yt-dlp -U && \
|
||||
/scripts/cleanup.sh
|
||||
|
||||
# Set default working directory.
|
||||
@@ -100,6 +102,3 @@ EXPOSE 2342 2443
|
||||
|
||||
# Copy app files.
|
||||
COPY --from=build --chown=root:root --chmod=755 /opt/photoprism/ /opt/photoprism
|
||||
|
||||
# Start app.
|
||||
CMD ["/scripts/cmd.sh", "/opt/photoprism/bin/photoprism", "start"]
|
@@ -42,8 +42,9 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
||||
DOCKER_ENV="prod" \
|
||||
TMPDIR="/tmp" \
|
||||
DEBIAN_FRONTEND="noninteractive" \
|
||||
TF_CPP_MIN_LOG_LEVEL="2" \
|
||||
MALLOC_ARENA_MAX="4" \
|
||||
TF_CPP_MIN_LOG_LEVEL=4 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
PROG="photoprism" \
|
||||
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
||||
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
||||
|
@@ -42,8 +42,9 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
||||
DOCKER_ENV="prod" \
|
||||
TMPDIR="/tmp" \
|
||||
DEBIAN_FRONTEND="noninteractive" \
|
||||
TF_CPP_MIN_LOG_LEVEL="2" \
|
||||
MALLOC_ARENA_MAX="4" \
|
||||
TF_CPP_MIN_LOG_LEVEL=4 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
PROG="photoprism" \
|
||||
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
||||
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
||||
|
@@ -42,8 +42,9 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
||||
DOCKER_ENV="prod" \
|
||||
TMPDIR="/tmp" \
|
||||
DEBIAN_FRONTEND="noninteractive" \
|
||||
TF_CPP_MIN_LOG_LEVEL="2" \
|
||||
MALLOC_ARENA_MAX="4" \
|
||||
TF_CPP_MIN_LOG_LEVEL=4 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
PROG="photoprism" \
|
||||
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
||||
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
||||
|
@@ -42,8 +42,9 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
||||
DOCKER_ENV="prod" \
|
||||
TMPDIR="/tmp" \
|
||||
DEBIAN_FRONTEND="noninteractive" \
|
||||
TF_CPP_MIN_LOG_LEVEL="2" \
|
||||
MALLOC_ARENA_MAX="4" \
|
||||
TF_CPP_MIN_LOG_LEVEL=4 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
PROG="photoprism" \
|
||||
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
||||
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
||||
@@ -100,6 +101,3 @@ EXPOSE 2342 2443
|
||||
|
||||
# Copy app files.
|
||||
COPY --from=build --chown=root:root --chmod=755 /opt/photoprism/ /opt/photoprism
|
||||
|
||||
# Start app.
|
||||
CMD ["/scripts/cmd.sh", "/opt/photoprism/bin/photoprism", "start"]
|
104
docker/photoprism/plucky/Dockerfile
Normal file
104
docker/photoprism/plucky/Dockerfile
Normal file
@@ -0,0 +1,104 @@
|
||||
##################################################### BUILD STAGE ######################################################
|
||||
FROM photoprism/develop:plucky AS build
|
||||
|
||||
# Copyright © 2018 - 2025 PhotoPrism UG. All rights reserved.
|
||||
#
|
||||
# Questions? Email us at hello@photoprism.app or visit our website to learn
|
||||
# more about our team, products and services: https://www.photoprism.app/
|
||||
|
||||
# Declare build parameters.
|
||||
ARG TARGETARCH
|
||||
ARG TARGETPLATFORM
|
||||
ARG BUILD_TAG
|
||||
|
||||
# Copy source to image.
|
||||
WORKDIR "/go/src/github.com/photoprism/photoprism"
|
||||
COPY . .
|
||||
|
||||
# Build app.
|
||||
RUN make all install DESTDIR=/opt/photoprism
|
||||
|
||||
################################################## PRODUCTION STAGE ####################################################
|
||||
#### Base Image: Ubuntu 25.04 (Plucky Puffin)
|
||||
FROM photoprism/develop:plucky-slim
|
||||
|
||||
# Add Open Container Initiative (OCI) annotations.
|
||||
# See: https://github.com/opencontainers/image-spec/blob/main/annotations.md
|
||||
LABEL org.opencontainers.image.title="PhotoPrism® (Ubuntu 25.04)"
|
||||
LABEL org.opencontainers.image.description="Ubuntu 25.04 (Plucky Puffin)"
|
||||
LABEL org.opencontainers.image.url="https://hub.docker.com/r/photoprism/photoprism"
|
||||
LABEL org.opencontainers.image.source="https://github.com/photoprism/photoprism"
|
||||
LABEL org.opencontainers.image.documentation="https://docs.photoprism.app/getting-started/"
|
||||
LABEL org.opencontainers.image.authors="PhotoPrism UG <hello@photoprism.app>"
|
||||
LABEL org.opencontainers.image.vendor="PhotoPrism UG"
|
||||
|
||||
# Declare build parameters.
|
||||
ARG TARGETARCH
|
||||
ARG BUILD_TAG
|
||||
|
||||
# Set environment variables, see https://docs.photoprism.app/getting-started/config-options/.
|
||||
ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
||||
DOCKER_TAG=$BUILD_TAG \
|
||||
DOCKER_ENV="prod" \
|
||||
TMPDIR="/tmp" \
|
||||
DEBIAN_FRONTEND="noninteractive" \
|
||||
TF_CPP_MIN_LOG_LEVEL=4 \
|
||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||
MALLOC_ARENA_MAX=2 \
|
||||
PROG="photoprism" \
|
||||
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
||||
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
||||
PHOTOPRISM_ORIGINALS_PATH="/photoprism/originals" \
|
||||
PHOTOPRISM_STORAGE_PATH="/photoprism/storage" \
|
||||
PHOTOPRISM_BACKUP_PATH="/photoprism/storage/backups" \
|
||||
PHOTOPRISM_LOG_FILENAME="/photoprism/storage/photoprism.log" \
|
||||
PHOTOPRISM_PID_FILENAME="/photoprism/storage/photoprism.pid" \
|
||||
PHOTOPRISM_DEBUG="false" \
|
||||
PHOTOPRISM_PUBLIC="false" \
|
||||
PHOTOPRISM_READONLY="false" \
|
||||
PHOTOPRISM_UPLOAD_NSFW="true" \
|
||||
PHOTOPRISM_DETECT_NSFW="false" \
|
||||
PHOTOPRISM_EXPERIMENTAL="false" \
|
||||
PHOTOPRISM_SITE_URL="http://localhost:2342/" \
|
||||
PHOTOPRISM_SITE_CAPTION="AI-Powered Photos App" \
|
||||
PHOTOPRISM_SITE_DESCRIPTION="" \
|
||||
PHOTOPRISM_SITE_AUTHOR="" \
|
||||
PHOTOPRISM_HTTP_HOST="0.0.0.0" \
|
||||
PHOTOPRISM_HTTP_PORT=2342 \
|
||||
PHOTOPRISM_DATABASE_DRIVER="sqlite" \
|
||||
PHOTOPRISM_DATABASE_SERVER="" \
|
||||
PHOTOPRISM_DATABASE_NAME="photoprism" \
|
||||
PHOTOPRISM_DATABASE_USER="photoprism" \
|
||||
PHOTOPRISM_DATABASE_PASSWORD="" \
|
||||
PHOTOPRISM_DISABLE_CHOWN="false" \
|
||||
PHOTOPRISM_DISABLE_WEBDAV="false" \
|
||||
PHOTOPRISM_DISABLE_SETTINGS="false" \
|
||||
PHOTOPRISM_DISABLE_BACKUPS="false" \
|
||||
PHOTOPRISM_DISABLE_EXIFTOOL="false" \
|
||||
PHOTOPRISM_DISABLE_PLACES="false" \
|
||||
PHOTOPRISM_DISABLE_TENSORFLOW="false" \
|
||||
PHOTOPRISM_DISABLE_FACES="false" \
|
||||
PHOTOPRISM_DISABLE_CLASSIFICATION="false" \
|
||||
PHOTOPRISM_RAW_PRESETS="false" \
|
||||
PHOTOPRISM_THUMB_UNCACHED="false" \
|
||||
PHOTOPRISM_AUTO_INDEX="300" \
|
||||
PHOTOPRISM_AUTO_IMPORT="-1" \
|
||||
PHOTOPRISM_INIT="https"
|
||||
|
||||
# Copy scripts.
|
||||
COPY --chown=root:root --chmod=755 /scripts/dist/ /scripts/
|
||||
|
||||
# Update pre-installed packages.
|
||||
RUN apt-get update && \
|
||||
apt-get -qq dist-upgrade && \
|
||||
yt-dlp -U && \
|
||||
/scripts/cleanup.sh
|
||||
|
||||
# Set default working directory.
|
||||
WORKDIR /photoprism
|
||||
|
||||
# Expose HTTP(S) ports.
|
||||
EXPOSE 2342 2443
|
||||
|
||||
# Copy app files.
|
||||
COPY --from=build --chown=root:root --chmod=755 /opt/photoprism/ /opt/photoprism
|
@@ -1,27 +0,0 @@
|
||||
build --action_env PYTHON_BIN_PATH="/usr/bin/python3"
|
||||
build --action_env PYTHON_LIB_PATH="/usr/lib/python3/dist-packages"
|
||||
build --python_path="/usr/bin/python3"
|
||||
build --action_env TF_NEED_OPENCL_SYCL="0"
|
||||
build --action_env TF_NEED_ROCM="0"
|
||||
build --action_env TF_NEED_CUDA="0"
|
||||
build --action_env TF_NEED_TENSORRT="0"
|
||||
build --action_env CUDA_TOOLKIT_PATH="/usr/local/cuda"
|
||||
build --action_env TF_CUDA_COMPUTE_CAPABILITIES="5.3"
|
||||
build --action_env TF_CUDA_CLANG="0"
|
||||
build --action_env TF_CUDA_VERSION="10"
|
||||
build --action_env GCC_HOST_COMPILER_PATH="/usr/bin/gcc-4.8"
|
||||
build --verbose_failures
|
||||
build:opt --copt=-Wno-sign-compare
|
||||
build:opt --conlyopt=-std=c11
|
||||
build:opt --cxxopt="-D_GLIBCXX_USE_CXX11_ABI=0"
|
||||
build:opt --host_conlyopt=-std=c11
|
||||
build:opt --host_cxxopt="-D_GLIBCXX_USE_CXX11_ABI=0"
|
||||
build:opt --host_copt=-Wno-sign-compare
|
||||
build:opt --define with_default_optimizations=true
|
||||
build:v2 --define=tf_api_version=2
|
||||
build:xla --define with_xla_support=true
|
||||
test --flaky_test_attempts=3
|
||||
test --test_size_filters=small,medium
|
||||
test --test_tag_filters=-benchmark-test,-no_oss,-oss_serial
|
||||
test --build_tag_filters=-benchmark-test,-no_oss
|
||||
build --action_env TF_CONFIGURE_IOS="0"
|
@@ -1,10 +1,13 @@
|
||||
FROM ubuntu:18.04
|
||||
FROM ubuntu:22.04
|
||||
|
||||
LABEL maintainer="PhotoPrism UG <hello@photoprism.app>"
|
||||
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
ENV TMP /tmp
|
||||
ENV EXTRA_BAZEL_ARGS "--host_javabase=@local_jdk//:jdk"
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
ENV TMP=/tmp
|
||||
|
||||
# see https://docs.docker.com/build/building/variables/#env-usage-example
|
||||
ARG TF_VERSION=2.18.0
|
||||
ENV TF_VERSION=$TF_VERSION
|
||||
|
||||
# apt default settings
|
||||
RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
|
||||
@@ -17,47 +20,32 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
|
||||
# Install dev / build dependencies
|
||||
RUN apt-get update && apt-get upgrade && \
|
||||
apt-get install \
|
||||
ca-certificates \
|
||||
build-essential \
|
||||
autoconf \
|
||||
automake \
|
||||
libtool \
|
||||
g++-4.8 \
|
||||
gcc-4.8 \
|
||||
libc6-dev \
|
||||
zlib1g-dev \
|
||||
libssl-dev \
|
||||
python3 \
|
||||
ca-certificates \
|
||||
curl \
|
||||
chrpath \
|
||||
pkg-config \
|
||||
unzip \
|
||||
zip \
|
||||
make \
|
||||
nano \
|
||||
wget \
|
||||
git \
|
||||
libtool \
|
||||
python3 \
|
||||
python3-git \
|
||||
openjdk-8-jdk
|
||||
lsb-release \
|
||||
software-properties-common \
|
||||
gnupg \
|
||||
jq \
|
||||
nano
|
||||
|
||||
# Use GCC 4.8 and Python 3 as default
|
||||
# See https://www.tensorflow.org/install/source#tested_build_configurations
|
||||
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 10 && \
|
||||
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 10 && \
|
||||
update-alternatives --install /usr/bin/python python /usr/bin/python3.6 10
|
||||
# Install bazelisk and llvm
|
||||
RUN wget https://apt.llvm.org/llvm.sh && chmod u+x llvm.sh && \
|
||||
./llvm.sh 17 && rm llvm.sh && \
|
||||
ln -s /usr/bin/python3 /usr/bin/python && \
|
||||
ln -s /usr/bin/clang-17 /usr/bin/clang && \
|
||||
ln -s /usr/bin/clang++-17 /usr/bin/clang++ && \
|
||||
ln -s /usr/bin/clang-cpp /usr/bin/clang-cpp && \
|
||||
export BAZELISK_VERSION=$(curl -L https://api.github.com/repos/bazelbuild/bazelisk/releases/latest | jq -r .tag_name) && \
|
||||
curl -L https://github.com/bazelbuild/bazelisk/releases/download/${BAZELISK_VERSION}/bazelisk-linux-amd64 -o /usr/bin/bazel && \
|
||||
chmod +x /usr/bin/bazel && \
|
||||
mkdir -p /home/tensorflow
|
||||
|
||||
# Download Bazel & TensorFlow
|
||||
WORKDIR "/home/tensorflow"
|
||||
RUN wget https://github.com/tensorflow/tensorflow/archive/v1.15.2.tar.gz
|
||||
RUN tar -xzf v1.15.2.tar.gz
|
||||
|
||||
# Install Bazel
|
||||
RUN wget https://github.com/bazelbuild/bazel/releases/download/0.24.1/bazel-0.24.1-linux-x86_64
|
||||
RUN mv bazel-0.24.1-linux-x86_64 /usr/local/bin/bazel && chmod 755 /usr/local/bin/bazel
|
||||
|
||||
# Configure TensorFlow
|
||||
WORKDIR "/home/tensorflow/tensorflow-1.15.2"
|
||||
COPY ./*.sh ./
|
||||
COPY ./.tf_configure.bazelrc .tf_configure.bazelrc
|
||||
COPY ./Makefile Makefile
|
||||
|
@@ -1,20 +1,26 @@
|
||||
TF_VERSION=1.15.2
|
||||
|
||||
# -march see https://gcc.gnu.org/onlinedocs/gcc-4.8.5/gcc/i386-and-x86-64-Options.html
|
||||
|
||||
all: libtensorflow libtensorflow-avx libtensorflow-avx2
|
||||
patch:
|
||||
git apply tensorflow-$(TF_VERSION).diff
|
||||
all: libtensorflow libtensorflow-ssse3 libtensorflow-avx libtensorflow-avx2 libtensorflow-vnni libtensorflow-avx512
|
||||
# Downloads the TensorFlow source code from GitHub and extracts it to a subdirectory:
|
||||
download:
|
||||
wget https://github.com/tensorflow/tensorflow/archive/v$(TF_VERSION).tar.gz
|
||||
tar -xzf v$(TF_VERSION).tar.gz
|
||||
cp .tf_configure.bazelrc Makefile *.sh tensorflow-$(TF_VERSION)
|
||||
cp Makefile *.sh tensorflow-$(TF_VERSION)
|
||||
# Clang command line argument reference:
|
||||
# https://clang.llvm.org/docs/ClangCommandLineReference.html#x86
|
||||
libtensorflow:
|
||||
bazel build --jobs 2 --config=opt //tensorflow:libtensorflow.so
|
||||
./create_archive.sh linux-cpu $(TF_VERSION)
|
||||
bazel build -c opt //tensorflow:libtensorflow.so --copt=-O2 --copt=-mno-avx --copt=-mno-avx2 --copt=-mno-fma --copt=-march=x86-64
|
||||
./create_archive.sh amd64 $(TF_VERSION)
|
||||
libtensorflow-ssse3:
|
||||
bazel build -c opt //tensorflow:libtensorflow.so --copt=-O2 --copt=-mno-avx --copt=-mno-avx2 --copt=-mno-fma --copt=-march=core2
|
||||
./create_archive.sh amd64-ssse3 $(TF_VERSION)
|
||||
libtensorflow-avx:
|
||||
bazel build --jobs 2 --config=opt //tensorflow:libtensorflow.so --copt=-march=core-avx-i --host_copt=-march=core-avx-i
|
||||
./create_archive.sh linux-avx $(TF_VERSION)
|
||||
bazel build -c opt //tensorflow:libtensorflow.so --copt=-O2 --copt=-mavx
|
||||
./create_archive.sh amd64-avx $(TF_VERSION)
|
||||
libtensorflow-avx2:
|
||||
bazel build --jobs 2 --config=opt //tensorflow:libtensorflow.so --copt=-march=core-avx2 --host_copt=-march=core-avx2
|
||||
./create_archive.sh linux-avx2 $(TF_VERSION)
|
||||
bazel build -c opt //tensorflow:libtensorflow.so --copt=-O2 --copt=-mavx2 --copt=-mfma --copt=-mfpmath=both --copt=-msse4.2
|
||||
./create_archive.sh amd64-avx2 $(TF_VERSION)
|
||||
libtensorflow-vnni:
|
||||
bazel build -c opt //tensorflow:libtensorflow.so --copt=-O2 --copt=-mavx2 --copt=-mavxvnni --copt=-mfma --copt=-mfpmath=both --copt=-msse4.2
|
||||
./create_archive.sh amd64-vnni $(TF_VERSION)
|
||||
libtensorflow-avx512:
|
||||
bazel build -c opt //tensorflow:libtensorflow.so --copt=-O2 --copt=-mavx2 --copt=-mavx512f --copt=-mavx512vnni --copt=-mfma --copt=-mfpmath=both --copt=-msse4.2
|
||||
./create_archive.sh amd64-avx512 $(TF_VERSION)
|
||||
|
@@ -1,31 +0,0 @@
|
||||
build --action_env PYTHON_BIN_PATH="/usr/bin/python3"
|
||||
build --action_env PYTHON_LIB_PATH="/usr/lib/python3/dist-packages"
|
||||
build --python_path="/usr/bin/python3"
|
||||
build --action_env TF_NEED_OPENCL_SYCL="0"
|
||||
build --action_env TF_NEED_ROCM="0"
|
||||
build --action_env TF_NEED_CUDA="0"
|
||||
build --action_env TF_NEED_TENSORRT="0"
|
||||
build --action_env CUDA_TOOLKIT_PATH="/usr/local/cuda"
|
||||
build --action_env TF_CUDA_COMPUTE_CAPABILITIES="5.3"
|
||||
build --action_env TF_CUDA_CLANG="0"
|
||||
build --action_env TF_CUDA_VERSION="10"
|
||||
build --action_env GCC_HOST_COMPILER_PATH="/usr/bin/gcc-4.8"
|
||||
build --verbose_failures
|
||||
build:opt --copt=-march=armv8-a
|
||||
build:opt --copt=-Wno-sign-compare
|
||||
build:opt --conlyopt=-std=c11
|
||||
build:opt --conlyopt=-D_XOPEN_SOURCE=600
|
||||
build:opt --cxxopt="-D_GLIBCXX_USE_CXX11_ABI=0"
|
||||
build:opt --host_copt=-march=armv8-a
|
||||
build:opt --host_conlyopt=-std=c11
|
||||
build:opt --host_conlyopt=-D_XOPEN_SOURCE=600
|
||||
build:opt --host_cxxopt="-D_GLIBCXX_USE_CXX11_ABI=0"
|
||||
build:opt --host_copt=-Wno-sign-compare
|
||||
build:opt --define with_default_optimizations=true
|
||||
build:v2 --define=tf_api_version=2
|
||||
build:xla --define with_xla_support=true
|
||||
test --flaky_test_attempts=3
|
||||
test --test_size_filters=small,medium
|
||||
test --test_tag_filters=-benchmark-test,-no_oss,-oss_serial
|
||||
test --build_tag_filters=-benchmark-test,-no_oss
|
||||
build --action_env TF_CONFIGURE_IOS="0"
|
@@ -1,10 +1,13 @@
|
||||
FROM ubuntu:18.04
|
||||
FROM ubuntu:22.04
|
||||
|
||||
LABEL maintainer="PhotoPrism UG <hello@photoprism.app>"
|
||||
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
ENV TMP /tmp
|
||||
ENV EXTRA_BAZEL_ARGS "--host_javabase=@local_jdk//:jdk"
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
ENV TMP=/tmp
|
||||
|
||||
# see https://docs.docker.com/build/building/variables/#env-usage-example
|
||||
ARG TF_VERSION=2.18.0
|
||||
ENV TF_VERSION=$TF_VERSION
|
||||
|
||||
# apt default settings
|
||||
RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
|
||||
@@ -17,48 +20,32 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
|
||||
# Install dev / build dependencies
|
||||
RUN apt-get update && apt-get upgrade && \
|
||||
apt-get install \
|
||||
ca-certificates \
|
||||
build-essential \
|
||||
autoconf \
|
||||
automake \
|
||||
libtool \
|
||||
g++-4.8 \
|
||||
gcc-4.8 \
|
||||
libc6-dev \
|
||||
zlib1g-dev \
|
||||
libssl-dev \
|
||||
python3 \
|
||||
ca-certificates \
|
||||
curl \
|
||||
chrpath \
|
||||
pkg-config \
|
||||
unzip \
|
||||
zip \
|
||||
make \
|
||||
nano \
|
||||
wget \
|
||||
git \
|
||||
libtool \
|
||||
python3 \
|
||||
python3-git \
|
||||
openjdk-8-jdk
|
||||
lsb-release \
|
||||
software-properties-common \
|
||||
gnupg \
|
||||
jq \
|
||||
nano
|
||||
|
||||
# Use GCC 4.8 and Python 3 as default
|
||||
# See https://www.tensorflow.org/install/source#tested_build_configurations
|
||||
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 10 && \
|
||||
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 10 && \
|
||||
update-alternatives --install /usr/bin/python python /usr/bin/python3.6 10
|
||||
# Install bazelisk and llvm
|
||||
RUN wget https://apt.llvm.org/llvm.sh && chmod u+x llvm.sh && \
|
||||
./llvm.sh 17 && rm llvm.sh && \
|
||||
ln -s /usr/bin/python3 /usr/bin/python && \
|
||||
ln -s /usr/bin/clang-17 /usr/bin/clang && \
|
||||
ln -s /usr/bin/clang++-17 /usr/bin/clang++ && \
|
||||
ln -s /usr/bin/clang-cpp /usr/bin/clang-cpp && \
|
||||
export BAZELISK_VERSION=$(curl -L https://api.github.com/repos/bazelbuild/bazelisk/releases/latest | jq -r .tag_name) && \
|
||||
curl -L https://github.com/bazelbuild/bazelisk/releases/download/${BAZELISK_VERSION}/bazelisk-linux-arm64 -o /usr/bin/bazel && \
|
||||
chmod +x /usr/bin/bazel && \
|
||||
mkdir -p /home/tensorflow
|
||||
|
||||
# Download Bazel & TensorFlow
|
||||
WORKDIR "/home/tensorflow"
|
||||
RUN wget https://github.com/tensorflow/tensorflow/archive/v1.15.2.tar.gz
|
||||
RUN tar -xzf v1.15.2.tar.gz
|
||||
|
||||
# Install Bazel
|
||||
# RUN wget https://github.com/bazelbuild/bazel/releases/download/0.24.1/bazel-0.24.1-linux-x86_64
|
||||
RUN wget https://github.com/guysoft/bazel-bin/raw/master/bazel-0.24.1-aarch64
|
||||
RUN mv bazel-0.24.1-aarch64 /usr/local/bin/bazel && chmod 755 /usr/local/bin/bazel
|
||||
|
||||
# Configure TensorFlow
|
||||
WORKDIR "/home/tensorflow/tensorflow-1.15.2"
|
||||
COPY ./*.sh ./
|
||||
COPY ./.tf_configure.bazelrc .tf_configure.bazelrc
|
||||
COPY ./Makefile Makefile
|
||||
COPY ./Makefile Makefile
|
||||
|
@@ -1,10 +1,11 @@
|
||||
TF_VERSION=1.15.2
|
||||
|
||||
# -march see https://gcc.gnu.org/onlinedocs/gcc-4.8.5/gcc/i386-and-x86-64-Options.html
|
||||
|
||||
all: libtensorflow
|
||||
patch:
|
||||
git apply tensorflow-$(TF_VERSION).diff
|
||||
# Downloads the TensorFlow source code from GitHub and extracts it to a subdirectory:
|
||||
download:
|
||||
wget https://github.com/tensorflow/tensorflow/archive/v$(TF_VERSION).tar.gz
|
||||
tar -xzf v$(TF_VERSION).tar.gz
|
||||
cp Makefile *.sh tensorflow-$(TF_VERSION)
|
||||
# Clang command line argument reference:
|
||||
# https://clang.llvm.org/docs/ClangCommandLineReference.html#aarch64
|
||||
libtensorflow:
|
||||
bazel build --jobs 2 --config=opt //tensorflow:libtensorflow.so --copt=-march=armv8-a --host_copt=-march=armv8-a
|
||||
bazel build -c opt //tensorflow:libtensorflow.so --copt=-O2 --copt=-march=armv8-a
|
||||
./create_archive.sh arm64 $(TF_VERSION)
|
||||
|
@@ -10,11 +10,17 @@ echo "Creating 'libtensorflow-$1-$2.tar.gz'...";
|
||||
rm -rf tmp
|
||||
mkdir -p tmp/lib/
|
||||
mkdir -p tmp/include/tensorflow/c/eager/
|
||||
cp bazel-bin/tensorflow/libtensorflow.so.$2 tmp/lib/libtensorflow.so
|
||||
cp bazel-bin/tensorflow/libtensorflow_framework.so.$2 tmp/lib/libtensorflow_framework.so
|
||||
cp tensorflow/c/eager/c_api.h tmp/include/tensorflow/c/eager/
|
||||
cp tensorflow/c/c_api.h tensorflow/c/c_api_experimental.h LICENSE tmp/include/tensorflow/c/
|
||||
(cd tmp && tar -czf ../libtensorflow-$1-$2.tar.gz .)
|
||||
du -h libtensorflow-$1-$2.tar.gz
|
||||
mkdir -p tmp/include/tensorflow/core/platform
|
||||
mkdir -p tmp/include/tsl/platform
|
||||
mkdir -p tmp/include/xla/tsl/c
|
||||
|
||||
echo "Done"
|
||||
cp -av bazel-bin/tensorflow/libtensorflow* tmp/lib/
|
||||
cp tensorflow/c/eager/*.h tmp/include/tensorflow/c/eager/
|
||||
cp tensorflow/c/*.h LICENSE tmp/include/tensorflow/c/
|
||||
cp tensorflow/core/platform/*.h tmp/include/tensorflow/core/platform
|
||||
cp third_party/xla/third_party/tsl/tsl/platform/*.h tmp/include/tsl/platform
|
||||
cp third_party/xla/xla/tsl/c/*.h tmp/include/xla/tsl/c
|
||||
(cd tmp && tar --exclude=*.params -czf /build/libtensorflow-$1-$2.tar.gz .)
|
||||
du -h /build/libtensorflow-$1-$2.tar.gz
|
||||
|
||||
echo "Done."
|
||||
|
@@ -10,11 +10,17 @@ echo "Creating 'libtensorflow-$1-$2.tar.gz'...";
|
||||
rm -rf tmp
|
||||
mkdir -p tmp/lib/
|
||||
mkdir -p tmp/include/tensorflow/c/eager/
|
||||
cp bazel-bin/tensorflow/libtensorflow.so.$2 tmp/lib/libtensorflow.so
|
||||
cp bazel-bin/tensorflow/libtensorflow_framework.so.$2 tmp/lib/libtensorflow_framework.so
|
||||
cp tensorflow/c/eager/c_api.h tmp/include/tensorflow/c/eager/
|
||||
cp tensorflow/c/c_api.h tensorflow/c/c_api_experimental.h LICENSE tmp/include/tensorflow/c/
|
||||
(cd tmp && tar -czf ../libtensorflow-$1-$2.tar.gz .)
|
||||
du -h libtensorflow-$1-$2.tar.gz
|
||||
mkdir -p tmp/include/tensorflow/core/platform
|
||||
mkdir -p tmp/include/tsl/platform
|
||||
mkdir -p tmp/include/xla/tsl/c
|
||||
|
||||
echo "Done"
|
||||
cp -av bazel-bin/tensorflow/libtensorflow* tmp/lib/
|
||||
cp tensorflow/c/eager/*.h tmp/include/tensorflow/c/eager/
|
||||
cp tensorflow/c/*.h LICENSE tmp/include/tensorflow/c/
|
||||
cp tensorflow/core/platform/*.h tmp/include/tensorflow/core/platform
|
||||
cp third_party/xla/third_party/tsl/tsl/platform/*.h tmp/include/tsl/platform
|
||||
cp third_party/xla/xla/tsl/c/*.h tmp/include/xla/tsl/c
|
||||
(cd tmp && tar --exclude=*.params -czf /build/libtensorflow-$1-$2.tar.gz .)
|
||||
du -h /build/libtensorflow-$1-$2.tar.gz
|
||||
|
||||
echo "Done."
|
||||
|
9
docker/tensorflow/cross/Dockerfile
Normal file
9
docker/tensorflow/cross/Dockerfile
Normal file
@@ -0,0 +1,9 @@
|
||||
ARG BUILDER_SHA2=06040763c500bd2ebaaa4585d4729c88d2c8ccec94baa7fbe9bbe3dc2827d79d
|
||||
FROM gcr.io/tensorflow-testing/ml-devinfra-linux-aarch64-cross-compile:infrastructure-public-image-${BUILDER_SHA2}
|
||||
|
||||
# see https://docs.docker.com/build/building/variables/#env-usage-example
|
||||
ARG TF_VERSION=2.18.0
|
||||
ENV TF_VERSION=$TF_VERSION
|
||||
|
||||
COPY ./create_archive.sh .
|
||||
COPY ./Makefile Makefile
|
10
docker/tensorflow/cross/Makefile
Normal file
10
docker/tensorflow/cross/Makefile
Normal file
@@ -0,0 +1,10 @@
|
||||
# -march see https://gcc.gnu.org/onlinedocs/gcc-4.8.5/gcc/i386-and-x86-64-Options.html
|
||||
|
||||
all: libtensorflow
|
||||
download:
|
||||
wget https://github.com/tensorflow/tensorflow/archive/v$(TF_VERSION).tar.gz
|
||||
tar -xzf v$(TF_VERSION).tar.gz
|
||||
cp Makefile *.sh tensorflow-$(TF_VERSION)
|
||||
libtensorflow:
|
||||
bazel build -c opt --config cross_compile_linux_arm64 //tensorflow:libtensorflow.so
|
||||
./create_archive.sh arm64 $(TF_VERSION)
|
14
docker/tensorflow/cross/build.sh
Executable file
14
docker/tensorflow/cross/build.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
DEFAULT_TF_VERSION=2.18.0
|
||||
|
||||
if [[ "$#" -ge 1 ]]; then
|
||||
TF_VERSION=$1
|
||||
elif [[ -z "$TF_VERSION" ]]; then
|
||||
TF_VERSION=$DEFAULT_TF_VERSION
|
||||
fi
|
||||
|
||||
SHA2_VERSION=$(curl -L https://raw.githubusercontent.com/tensorflow/tensorflow/refs/tags/v${TF_VERSION}/tensorflow/tools/toolchains/cross_compile/config/BUILD | \
|
||||
grep container-image | awk -F'@' '{ print $2 }' | awk -F':' '{ print $2 }' | tr -d '",')
|
||||
|
||||
docker build --build-arg BUILDER_SHA2=$SHA2_VERSION --build-arg TF_VERSION=$TF_VERSION -t photoprism/tensorflow:$TF_VERSION-cross .
|
26
docker/tensorflow/cross/create_archive.sh
Executable file
26
docker/tensorflow/cross/create_archive.sh
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [[ -z $1 ]] || [[ -z $2 ]]; then
|
||||
echo "Usage: $0 [platform] [tf-version]" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Creating 'libtensorflow-$1-$2.tar.gz'...";
|
||||
|
||||
rm -rf tmp
|
||||
mkdir -p tmp/lib/
|
||||
mkdir -p tmp/include/tensorflow/c/eager/
|
||||
mkdir -p tmp/include/tensorflow/core/platform
|
||||
mkdir -p tmp/include/tsl/platform
|
||||
mkdir -p tmp/include/xla/tsl/c
|
||||
|
||||
cp -av bazel-bin/tensorflow/libtensorflow* tmp/lib/
|
||||
cp tensorflow/c/eager/*.h tmp/include/tensorflow/c/eager/
|
||||
cp tensorflow/c/*.h LICENSE tmp/include/tensorflow/c/
|
||||
cp tensorflow/core/platform/*.h tmp/include/tensorflow/core/platform
|
||||
cp third_party/xla/third_party/tsl/tsl/platform/*.h tmp/include/tsl/platform
|
||||
cp third_party/xla/xla/tsl/c/*.h tmp/include/xla/tsl/c
|
||||
(cd tmp && tar --exclude=*.params -czf /build/libtensorflow-$1-$2.tar.gz .)
|
||||
du -h /build/libtensorflow-$1-$2.tar.gz
|
||||
|
||||
echo "Done."
|
@@ -1,36 +0,0 @@
|
||||
build --action_env PYTHON_BIN_PATH="/usr/bin/python"
|
||||
build --action_env PYTHON_LIB_PATH="/usr/lib/python2.7/dist-packages"
|
||||
build --python_path="/usr/bin/python"
|
||||
build --action_env TF_NEED_OPENCL_SYCL="0"
|
||||
build --action_env TF_NEED_ROCM="0"
|
||||
build --action_env TF_NEED_CUDA="1"
|
||||
build --action_env TF_NEED_TENSORRT="1"
|
||||
build --action_env CUDA_TOOLKIT_PATH="/usr/local/cuda"
|
||||
build --action_env TF_CUDA_COMPUTE_CAPABILITIES="5.3"
|
||||
build --action_env TF_CUDA_CLANG="0"
|
||||
build --action_env TF_CUDA_VERSION="10"
|
||||
build --action_env GCC_HOST_COMPILER_PATH="/usr/bin/gcc"
|
||||
build --config=cuda
|
||||
build --config=nonccl
|
||||
build --verbose_failures
|
||||
build --jobs 2
|
||||
build:opt --copt=-march=armv8-a
|
||||
build:opt --copt=-Wno-sign-compare
|
||||
build:opt --conlyopt=-std=c11
|
||||
build:opt --conlyopt=-D_XOPEN_SOURCE=600
|
||||
build:opt --cxxopt="-D_GLIBCXX_USE_CXX11_ABI=0"
|
||||
build:opt --host_copt=-march=armv8-a
|
||||
build:opt --host_conlyopt=-std=c11
|
||||
build:opt --host_conlyopt=-D_XOPEN_SOURCE=600
|
||||
build:opt --host_cxxopt="-D_GLIBCXX_USE_CXX11_ABI=0"
|
||||
build:opt --host_copt=-Wno-sign-compare
|
||||
build:opt --define with_default_optimizations=true
|
||||
build:v2 --define=tf_api_version=2
|
||||
build:xla --define with_xla_support=true
|
||||
test --flaky_test_attempts=3
|
||||
test --test_size_filters=small,medium
|
||||
test --test_tag_filters=-benchmark-test,-no_oss,-oss_serial
|
||||
test --build_tag_filters=-benchmark-test,-no_oss
|
||||
test --test_tag_filters=-gpu
|
||||
test --build_tag_filters=-gpu
|
||||
build --action_env TF_CONFIGURE_IOS="0"
|
@@ -1,14 +1,10 @@
|
||||
TF_VERSION=1.15.2
|
||||
|
||||
# -march see https://gcc.gnu.org/onlinedocs/gcc-4.8.5/gcc/i386-and-x86-64-Options.html
|
||||
|
||||
all: libtensorflow
|
||||
patch:
|
||||
git apply tensorflow-$(TF_VERSION).diff
|
||||
download:
|
||||
wget https://github.com/tensorflow/tensorflow/archive/v$(TF_VERSION).tar.gz
|
||||
tar -xzf v$(TF_VERSION).tar.gz
|
||||
cp .tf_configure.bazelrc Makefile ../*.sh tensorflow-$(TF_VERSION)
|
||||
cp Makefile *.sh tensorflow-$(TF_VERSION)
|
||||
libtensorflow:
|
||||
bazel build --jobs 2 --config=opt //tensorflow:libtensorflow.so
|
||||
bazel build -c opt //tensorflow:libtensorflow.so --copt=-march=armv8-a
|
||||
./create_archive.sh jetson-nano $(TF_VERSION)
|
||||
|
26
docker/tensorflow/jetson-nano/create_archive.sh
Executable file
26
docker/tensorflow/jetson-nano/create_archive.sh
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [[ -z $1 ]] || [[ -z $2 ]]; then
|
||||
echo "Usage: $0 [platform] [tf-version]" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Creating 'libtensorflow-$1-$2.tar.gz'...";
|
||||
|
||||
rm -rf tmp
|
||||
mkdir -p tmp/lib/
|
||||
mkdir -p tmp/include/tensorflow/c/eager/
|
||||
mkdir -p tmp/include/tensorflow/core/platform
|
||||
mkdir -p tmp/include/tsl/platform
|
||||
mkdir -p tmp/include/xla/tsl/c
|
||||
|
||||
cp -av bazel-bin/tensorflow/libtensorflow* tmp/lib/
|
||||
cp tensorflow/c/eager/*.h tmp/include/tensorflow/c/eager/
|
||||
cp tensorflow/c/*.h LICENSE tmp/include/tensorflow/c/
|
||||
cp tensorflow/core/platform/*.h tmp/include/tensorflow/core/platform
|
||||
cp third_party/xla/third_party/tsl/tsl/platform/*.h tmp/include/tsl/platform
|
||||
cp third_party/xla/xla/tsl/c/*.h tmp/include/xla/tsl/c
|
||||
(cd tmp && tar --exclude=*.params -czf /build/libtensorflow-$1-$2.tar.gz .)
|
||||
du -h /build/libtensorflow-$1-$2.tar.gz
|
||||
|
||||
echo "Done."
|
@@ -1,27 +0,0 @@
|
||||
build --action_env PYTHON_BIN_PATH="/usr/local/bin/python3"
|
||||
build --action_env PYTHON_LIB_PATH="/usr/local/lib/python3.7/site-packages"
|
||||
build --python_path="/usr/local/bin/python3"
|
||||
build --action_env TF_NEED_OPENCL_SYCL="0"
|
||||
build --action_env TF_NEED_ROCM="0"
|
||||
build --action_env TF_NEED_CUDA="0"
|
||||
build --action_env TF_NEED_TENSORRT="0"
|
||||
build --action_env CUDA_TOOLKIT_PATH="/usr/local/cuda"
|
||||
build --action_env TF_CUDA_COMPUTE_CAPABILITIES="5.3"
|
||||
build --action_env TF_CUDA_CLANG="0"
|
||||
build --action_env TF_CUDA_VERSION="10"
|
||||
build --action_env GCC_HOST_COMPILER_PATH="/usr/bin/gcc"
|
||||
build --verbose_failures
|
||||
build:opt --copt=-Wno-sign-compare
|
||||
build:opt --conlyopt=-std=c11
|
||||
build:opt --cxxopt="-D_GLIBCXX_USE_CXX11_ABI=0"
|
||||
build:opt --host_conlyopt=-std=c11
|
||||
build:opt --host_cxxopt="-D_GLIBCXX_USE_CXX11_ABI=0"
|
||||
build:opt --host_copt=-Wno-sign-compare
|
||||
build:opt --define with_default_optimizations=true
|
||||
build:v2 --define=tf_api_version=2
|
||||
build:xla --define with_xla_support=true
|
||||
test --flaky_test_attempts=3
|
||||
test --test_size_filters=small,medium
|
||||
test --test_tag_filters=-benchmark-test,-no_oss,-oss_serial
|
||||
test --build_tag_filters=-benchmark-test,-no_oss
|
||||
build --action_env TF_CONFIGURE_IOS="0"
|
@@ -1,20 +1,16 @@
|
||||
TF_VERSION=1.15.2
|
||||
|
||||
# -march see https://gcc.gnu.org/onlinedocs/gcc-4.8.5/gcc/i386-and-x86-64-Options.html
|
||||
|
||||
all: libtensorflow libtensorflow-avx libtensorflow-avx2
|
||||
patch:
|
||||
git apply tensorflow-$(TF_VERSION).diff
|
||||
download:
|
||||
wget https://github.com/tensorflow/tensorflow/archive/v$(TF_VERSION).tar.gz
|
||||
tar -xzf v$(TF_VERSION).tar.gz
|
||||
cp .tf_configure.bazelrc Makefile ../*.sh tensorflow-$(TF_VERSION)
|
||||
cp Makefile *.sh tensorflow-$(TF_VERSION)
|
||||
libtensorflow:
|
||||
bazel build --jobs 2 --config=opt //tensorflow:libtensorflow.so
|
||||
bazel build -c opt //tensorflow:libtensorflow.so
|
||||
./create_archive.sh osx-cpu $(TF_VERSION)
|
||||
libtensorflow-avx:
|
||||
bazel build --jobs 2 --config=opt //tensorflow:libtensorflow.so --copt=-march=core-avx-i --host_copt=-march=core-avx-i
|
||||
bazel build -c opt //tensorflow:libtensorflow.so --copt=-mavx
|
||||
./create_archive.sh osx-avx $(TF_VERSION)
|
||||
libtensorflow-avx2:
|
||||
bazel build --jobs 2 --config=opt //tensorflow:libtensorflow.so --copt=-march=core-avx2 --host_copt=-march=core-avx2
|
||||
./create_archive.sh osx-avx2 $(TF_VERSION)
|
||||
bazel build -c opt //tensorflow:libtensorflow.so --copt=-mavx2
|
||||
./create_archive.sh osx-avx2 $(TF_VERSION)
|
||||
|
@@ -1,14 +0,0 @@
|
||||
coverage/
|
||||
node_modules/
|
||||
tests/screenshots/
|
||||
tests/acceptance/screenshots/
|
||||
tests/upload-files/
|
||||
*.html
|
||||
.idea
|
||||
.github
|
||||
.tmp
|
||||
.local
|
||||
.cache
|
||||
.var
|
||||
|
||||
!**/.eslintrc.js
|
@@ -1,108 +0,0 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
commonjs: true,
|
||||
es2021: true,
|
||||
node: true,
|
||||
mocha: true,
|
||||
},
|
||||
extends: [
|
||||
"eslint:recommended",
|
||||
"plugin:vue/recommended",
|
||||
"plugin:prettier/recommended",
|
||||
"plugin:vue/base",
|
||||
"plugin:vuetify/base",
|
||||
],
|
||||
settings: {
|
||||
"prettier/prettier": {
|
||||
// Settings for how to process Vue SFC Blocks
|
||||
SFCBlocks: {
|
||||
template: false,
|
||||
script: false,
|
||||
style: false,
|
||||
},
|
||||
|
||||
// Use prettierrc for prettier options or not (default: `true`)
|
||||
usePrettierrc: true,
|
||||
|
||||
// Set the options for `prettier.getFileInfo`.
|
||||
// @see https://prettier.io/docs/en/api.html#prettiergetfileinfofilepath-options
|
||||
fileInfoOptions: {
|
||||
// Path to ignore file (default: `'.prettierignore'`)
|
||||
// Notice that the ignore file is only used for this plugin
|
||||
ignorePath: ".testignore",
|
||||
|
||||
// Process the files in `node_modules` or not (default: `false`)
|
||||
withNodeModules: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
parserOptions: {
|
||||
ecmaVersion: "latest",
|
||||
sourceType: "module",
|
||||
},
|
||||
rules: {
|
||||
// 'comma-dangle': ['error', 'always-multiline'],
|
||||
"indent": ["error", 2, { SwitchCase: 1 }],
|
||||
"linebreak-style": ["error", "unix"],
|
||||
"quotes": [
|
||||
"off",
|
||||
"double",
|
||||
{
|
||||
avoidEscape: true,
|
||||
allowTemplateLiterals: true,
|
||||
},
|
||||
],
|
||||
"semi": ["error", "always"],
|
||||
"no-unused-vars": ["warn"],
|
||||
"no-console": 0,
|
||||
"no-case-declarations": 0,
|
||||
"no-prototype-builtins": 0,
|
||||
"vue/no-v-text-v-html-on-component": 0,
|
||||
"vue/no-v-model-argument": 0,
|
||||
"vue/valid-model-definition": 0,
|
||||
"vue/valid-attribute-name": 0,
|
||||
"vue/singleline-html-element-content-newline": [
|
||||
"off",
|
||||
{
|
||||
ignoreWhenNoAttributes: true,
|
||||
ignoreWhenEmpty: true,
|
||||
ignores: [
|
||||
"pre",
|
||||
"textarea",
|
||||
"span",
|
||||
"translate",
|
||||
"a",
|
||||
"v-icon",
|
||||
"v-text-field",
|
||||
"v-input",
|
||||
"v-select",
|
||||
"v-switch",
|
||||
"v-checkbox",
|
||||
"v-img",
|
||||
],
|
||||
externalIgnores: [],
|
||||
},
|
||||
],
|
||||
"vue/first-attribute-linebreak": [
|
||||
"error",
|
||||
{
|
||||
singleline: "ignore",
|
||||
multiline: "ignore",
|
||||
},
|
||||
],
|
||||
"prettier/prettier": [
|
||||
"warn",
|
||||
{
|
||||
printWidth: 120,
|
||||
semi: true,
|
||||
singleQuote: false,
|
||||
bracketSpacing: true,
|
||||
trailingComma: "es5",
|
||||
htmlWhitespaceSensitivity: "css",
|
||||
quoteProps: "consistent",
|
||||
proseWrap: "never",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
@@ -5,8 +5,10 @@ tests/acceptance/screenshots/
|
||||
tests/upload-files/
|
||||
*.html
|
||||
.idea
|
||||
.codex
|
||||
.github
|
||||
.tmp
|
||||
.local
|
||||
.cache
|
||||
.gocache
|
||||
.var
|
||||
|
106
frontend/CODEMAP.md
Normal file
106
frontend/CODEMAP.md
Normal file
@@ -0,0 +1,106 @@
|
||||
PhotoPrism — Frontend CODEMAP
|
||||
|
||||
Purpose
|
||||
- Help agents and contributors navigate the Vue 3 + Vuetify 3 app quickly and make safe changes.
|
||||
- Use Makefile targets and scripts in `frontend/package.json` as sources of truth.
|
||||
|
||||
Quick Start
|
||||
- Build once: `make -C frontend build`
|
||||
- Watch for changes (inside dev container is fine):
|
||||
- `make watch-js` from repo root, or
|
||||
- `cd frontend && npm run watch`
|
||||
- Unit tests (Vitest): `make vitest-watch` / `make vitest-coverage` or `cd frontend && npm run test`
|
||||
|
||||
Directory Map (src)
|
||||
- `src/app.vue` — root component; UI shell
|
||||
- `src/app.js` — app bootstrap: creates Vue app, installs Vuetify + plugins, configures router, mounts to `#app`
|
||||
- `src/app/routes.js` — all route definitions (guards, titles, meta)
|
||||
- `src/app/session.js` — `$config` and `$session` singletons wired from server-provided `window.__CONFIG__` and storage
|
||||
- `src/common/*` — framework-agnostic helpers: `$api` (Axios), `$notify`, `$view`, `$event` (PubSub), i18n (`gettext`), util, fullscreen, map utils, websocket
|
||||
- `src/component/*` — Vue components; `src/component/components.js` registers global components
|
||||
- `src/page/*` — route views (Albums, Photos, Places, Settings, Admin, Discover, Help, Login, etc.)
|
||||
- `src/model/*` — REST models; base `Rest` class (`model/rest.js`) wraps Axios CRUD for collections and entities
|
||||
- `src/options/*` — UI/theme options, formats, auth options
|
||||
- `src/css/*` — styles loaded by Webpack
|
||||
- `src/locales/*` — gettext catalogs; extraction/compile scripts in `package.json`
|
||||
|
||||
Runtime & Plugins
|
||||
- Vue 3 + Vuetify 3 (`createVuetify`) with MDI icons; themes from `src/options/themes.js`
|
||||
- Router: Vue Router 4, history base at `$config.baseUri + "/library/"`
|
||||
- I18n: `vue3-gettext` via `common/gettext.js`; extraction with `npm run gettext-extract`, compile with `npm run gettext-compile`
|
||||
- HTML sanitization: `vue-3-sanitize` + `vue-sanitize-directive`
|
||||
- Tooltips: `floating-vue`
|
||||
- Video: HLS.js assigned to `window.Hls`
|
||||
- PWA: `@lcdp/offline-plugin/runtime` installs when `baseUri === ""`
|
||||
- WebSocket: `src/common/websocket.js` publishes `websocket.*` events, used by `$session` for client info
|
||||
|
||||
HTTP Client
|
||||
- Axios instance: `src/common/api.js`
|
||||
- Base URL: `window.__CONFIG__.apiUri` (or `/api/v1` in tests)
|
||||
- Adds `X-Auth-Token`, `X-Client-Uri`, `X-Client-Version`
|
||||
- Interceptors drive global progress notifications and token refresh via headers `X-Preview-Token`/`X-Download-Token`
|
||||
|
||||
Auth, Session, and Config
|
||||
- `$session`: `src/common/session.js` — stores `X-Auth-Token` and `session.id` in storage; provides guards and default routes
|
||||
- `$config`: `src/common/config.js` — reactive view of server config and user settings; sets theme, language, limits; exposes `deny()` for feature flags
|
||||
- Route guards live in `src/app.js` (router `beforeEach`/`afterEach`) and use `$session` + `$config`
|
||||
|
||||
Models (REST)
|
||||
- Base class: `src/model/rest.js` provides `search`, `find`, `save`, `update`, `remove` for concrete models (`photo`, `album`, `label`, `subject`, etc.)
|
||||
- Pagination headers used: `X-Count`, `X-Limit`, `X-Offset`
|
||||
|
||||
Routing Conventions
|
||||
- Add pages under `src/page/<area>/...` and import them in `src/app/routes.js`
|
||||
- Set `meta.requiresAuth`, `meta.admin`, and `meta.settings` as needed
|
||||
- Use `meta.title` for translated titles; `router.afterEach` updates `document.title`
|
||||
|
||||
Theming & UI
|
||||
- Themes: `src/options/themes.js` registered in Vuetify; default comes from `$config.values.settings.ui.theme`
|
||||
- Global components: register in `src/component/components.js` when they are broadly reused
|
||||
|
||||
Testing
|
||||
- Vitest config: `frontend/vitest.config.js` (Vue plugin, alias map to `src/*`), `tests/vitest/**/*`
|
||||
- Run: `cd frontend && npm run test` (or `make test-js` from repo root)
|
||||
- Acceptance: TestCafe configs in `frontend/tests/acceptance`; run against a live server
|
||||
|
||||
Build & Tooling
|
||||
- Webpack is used for bundling; scripts in `frontend/package.json`:
|
||||
- `npm run build` (prod), `npm run build-dev` (dev), `npm run watch`
|
||||
- Lint/format: `npm run lint`, `npm run fmt`
|
||||
- Security scan: `npm run security:scan` (checks `--ignore-scripts` and forbids `v-html`)
|
||||
- Make targets (from repo root): `make build-js`, `make watch-js`, `make test-js`
|
||||
|
||||
Common How‑Tos
|
||||
- Add a page
|
||||
- Create `src/page/<name>.vue` (or nested directory)
|
||||
- Add route in `src/app/routes.js` with `name`, `path`, `component`, and `meta`
|
||||
- Use `$api` for data, `$notify` for UX, `$session` for guards
|
||||
|
||||
- Add a REST model
|
||||
- Create `src/model/<thing>.js` extending `Rest` and implement `static getCollectionResource()` + `static getModelName()`
|
||||
- Use in pages/components for CRUD
|
||||
|
||||
- Call a backend endpoint
|
||||
- Use `$api.get/post/put/delete` from `src/common/api.js`
|
||||
- For auth: `$session.setAuthToken(token)` sets header; router guards redirect to `login` when needed
|
||||
|
||||
- Add translations
|
||||
- Wrap strings with `$gettext(...)` / `$pgettext(...)`
|
||||
- Extract: `npm run gettext-extract`; compile: `npm run gettext-compile`
|
||||
|
||||
Conventions & Safety
|
||||
- Avoid `v-html`; use `v-sanitize` or `$util.sanitizeHtml()` (build enforces this)
|
||||
- Keep big components lazy if needed; split views logically under `src/page`
|
||||
- Respect aliases in `vitest.config.js` when importing (`app`, `common`, `component`, `model`, `options`, `page`)
|
||||
|
||||
Frequently Touched Files
|
||||
- Bootstrap: `src/app.js`, `src/app.vue`
|
||||
- Router: `src/app/routes.js`
|
||||
- HTTP: `src/common/api.js`
|
||||
- Session/Config: `src/common/session.js`, `src/common/config.js`
|
||||
- Models: `src/model/rest.js` and concrete models (`photo.js`, `album.js`, ...)
|
||||
- Global components: `src/component/components.js`
|
||||
|
||||
See Also
|
||||
- Backend CODEMAP at repo root (`CODEMAP.md`) for API and server internals
|
||||
- AGENTS.md for repo-wide rules and test tips
|
@@ -3,24 +3,58 @@
|
||||
# Questions? Email us at hello@photoprism.app or visit our website to learn
|
||||
# more about our team, products and services: https://www.photoprism.app/
|
||||
|
||||
UID := $(shell id -u)
|
||||
GID := $(shell id -g)
|
||||
PWD := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
|
||||
NODE_IMAGE ?= node:lts
|
||||
|
||||
define DOCKER_NPM
|
||||
docker run --rm -it \
|
||||
-v "$(PWD)":/app \
|
||||
-w /app \
|
||||
--user "$(UID):$(GID)" \
|
||||
--read-only --tmpfs /tmp \
|
||||
-v ~/.cache/npm:/npm-cache \
|
||||
-e NPM_CONFIG_CACHE=/npm-cache \
|
||||
-e NPM_CONFIG_AUDIT=false \
|
||||
-e NPM_CONFIG_FUND=false \
|
||||
-e NO_UPDATE_NOTIFIER=true \
|
||||
--cap-drop ALL --security-opt no-new-privileges --pids-limit 256 \
|
||||
$(NODE_IMAGE) sh -lc
|
||||
endef
|
||||
|
||||
# Declare "make" targets.
|
||||
all: install build
|
||||
dep: install-npm install-testcafe install
|
||||
dep-list:
|
||||
npx npm-check-updates
|
||||
help: list
|
||||
list:
|
||||
@awk '/^[[:alnum:]]+[^[:space:]]+:/ {printf "%s",substr($$1,1,length($$1)-1); if (match($$0,/#/)) {desc=substr($$0,RSTART+1); sub(/^[[:space:]]+/,"",desc); printf " - %s\n",desc} else printf "\n" }' "$(firstword $(MAKEFILE_LIST))"
|
||||
notice:
|
||||
@echo "Creating license report for frontend dependencies..."
|
||||
license-report --only=prod --config=.report.json > NOTICE
|
||||
install-npm:
|
||||
sudo npm install --unsafe-perm=true --allow-root -g npm@latest npm-check-updates@latest license-report@latest
|
||||
# Keep scripts enabled for npm itself; split other globals and disable scripts for safety
|
||||
sudo npm install -g npm@latest
|
||||
sudo npm install -g --ignore-scripts --no-fund --no-audit --no-update-notifier npm-check-updates@latest license-report@latest
|
||||
install-testcafe:
|
||||
npm install -g testcafe@latest
|
||||
npm install -g --ignore-scripts --no-fund --no-audit --no-update-notifier testcafe@latest
|
||||
install-eslint:
|
||||
npm install -g eslint@8 eslint-config-prettier eslint-config-standard eslint-formatter-pretty eslint-plugin-html eslint-plugin-import eslint-plugin-node eslint-plugin-prettier eslint-plugin-promise eslint-plugin-vue eslint-webpack-plugin vue-eslint-parser prettier
|
||||
install:
|
||||
npm install --no-update-notifier --no-audit
|
||||
update:
|
||||
npm update
|
||||
npm install -g --ignore-scripts --no-fund --no-audit --no-update-notifier eslint globals @eslint/eslintrc @eslint/js eslint-config-prettier eslint-formatter-pretty eslint-plugin-html eslint-plugin-import eslint-plugin-node eslint-plugin-prettier eslint-plugin-promise eslint-plugin-vue eslint-webpack-plugin vue-eslint-parser prettier
|
||||
upgrade:
|
||||
$(info Securely upgrading NPM dependencies...)
|
||||
$(DOCKER_NPM) 'npx -y npm@latest update --save --package-lock --ignore-scripts --no-fund --no-audit --no-update-notifier && npx -y npm@latest install --ignore-scripts --no-audit --no-fund --no-update-notifier'
|
||||
npm-install:
|
||||
$(info Installing NPM dependencies...)
|
||||
npm install --ignore-scripts --no-fund --no-audit --no-update-notifier
|
||||
install: npm-install
|
||||
npm-update:
|
||||
$(info Updating NPM dependencies in package.lock and package-lock.json...)
|
||||
npm update --save --package-lock --ignore-scripts --no-fund --no-audit --no-update-notifier
|
||||
update: npm-update npm-install
|
||||
security-check: # Scan for missing --ignore-scripts and unsafe v-html
|
||||
npm run -s security:scan
|
||||
watch:
|
||||
npm run watch
|
||||
build:
|
||||
@@ -31,8 +65,6 @@ fmt:
|
||||
npm run fmt
|
||||
test:
|
||||
npm run test
|
||||
upgrade:
|
||||
npm run upgrade
|
||||
testcafe:
|
||||
npm run testcafe
|
||||
acceptance-local:
|
||||
|
199
frontend/NOTICE
199
frontend/NOTICE
@@ -1,97 +1,102 @@
|
||||
Package License Copyright
|
||||
------- ------- ---------
|
||||
@babel/cli MIT The Babel Team (https://babel.dev/team)
|
||||
@babel/core MIT The Babel Team (https://babel.dev/team)
|
||||
@babel/plugin-transform-runtime MIT The Babel Team (https://babel.dev/team)
|
||||
@babel/preset-env MIT The Babel Team (https://babel.dev/team)
|
||||
@babel/register MIT The Babel Team (https://babel.dev/team)
|
||||
@babel/runtime MIT The Babel Team (https://babel.dev/team)
|
||||
@lcdp/offline-plugin MIT Le Comptoir Des Pharmacies <webmaster@lecomptoirdespharmacies.fr>
|
||||
@mdi/font Apache-2.0 Austin Andrews
|
||||
@vue/compiler-sfc MIT Evan You
|
||||
@vvo/tzdb MIT Vincent Voyer <vincent@codeagain.com>
|
||||
axios MIT Matt Zabriskie
|
||||
axios-mock-adapter MIT Colin Timmermans <colintimmermans@gmail.com>
|
||||
babel-loader MIT Luis Couto <hello@luiscouto.pt>
|
||||
babel-plugin-istanbul BSD-3-Clause Thai Pangsakulyanont @dtinth
|
||||
browserslist MIT Andrey Sitnik <andrey@sitnik.ru>
|
||||
chai MIT Jake Luer <jake@alogicalparadox.com>
|
||||
cheerio MIT Matt Mueller <mattmuelle@gmail.com>
|
||||
chrome-finder ISC gwuhaolin
|
||||
core-js MIT Denis Pushkarev zloirock@zloirock.ru http://zloirock.ru
|
||||
cross-env MIT Kent C. Dodds <me@kentcdodds.com> (https://kentcdodds.com)
|
||||
css-loader MIT Tobias Koppers @sokra
|
||||
cssnano MIT Ben Briggs beneb.info@gmail.com http://beneb.info
|
||||
easygettext MIT Polyconseil
|
||||
eslint MIT Nicholas C. Zakas <nicholas+npm@nczconsulting.com>
|
||||
eslint-config-prettier MIT Simon Lydell
|
||||
eslint-formatter-pretty MIT Sindre Sorhus sindresorhus@gmail.com https://sindresorhus.com
|
||||
eslint-plugin-html ISC n/a
|
||||
eslint-plugin-import MIT Ben Mosher <me@benmosher.com>
|
||||
eslint-plugin-node MIT Toru Nagashima
|
||||
eslint-plugin-prettier MIT Teddy Katz
|
||||
eslint-plugin-promise ISC jden <jason@denizac.org>
|
||||
eslint-plugin-vue MIT Toru Nagashima (https://github.com/mysticatea)
|
||||
eslint-plugin-vuetify MIT Kael Watts-Deuchar <kaelwd@gmail.com>
|
||||
eslint-webpack-plugin MIT Ricardo Gobbo de Souza <ricardogobbosouza@yahoo.com.br>
|
||||
eventsource-polyfill MIT amvtek <devel@amvtek.com>
|
||||
file-loader MIT Tobias Koppers @sokra
|
||||
file-saver MIT Eli Grey <me@eligrey.com>
|
||||
floating-vue MIT Guillaume Chau <guillaume.b.chau@gmail.com>
|
||||
hls.js Apache-2.0 n/a
|
||||
i MIT Pavan Kumar Sunkara <pavan.sss1991@gmail.com> (pksunkara.github.com)
|
||||
karma MIT Vojta Jína <vojta.jina@gmail.com>
|
||||
karma-chrome-launcher MIT Vojta Jina <vojta.jina@gmail.com>
|
||||
karma-coverage-istanbul-reporter MIT Matt Lewis
|
||||
karma-htmlfile-reporter MIT Matthias Schuetz MatthiasSchuetz@gmx.de
|
||||
karma-mocha MIT Vojta Jina <vojta.jina@gmail.com>
|
||||
karma-verbose-reporter MIT Pier Fumagalli pier@usrz.com
|
||||
karma-webpack MIT Tobias Koppers @sokra
|
||||
luxon MIT Isaac Cambron
|
||||
maplibre-gl BSD-3-Clause n/a
|
||||
memoize-one MIT Alex Reardon <alexreardon@gmail.com>
|
||||
mini-css-extract-plugin MIT Tobias Koppers @sokra
|
||||
minimist MIT James Halliday mail@substack.net http://substack.net
|
||||
mocha MIT TJ Holowaychuk <tj@vision-media.ca>
|
||||
node-storage-shim ISC Michael Nahkies
|
||||
passive-events-support MIT Ignas Damunskis <ignas3run@gmail.com>
|
||||
photoswipe MIT Dmytro Semenov (https://dimsemenov.com)
|
||||
postcss MIT Andrey Sitnik <andrey@sitnik.ru>
|
||||
postcss-import MIT Maxime Thirouin
|
||||
postcss-loader MIT Andrey Sitnik <andrey@sitnik.ru>
|
||||
postcss-preset-env MIT-0 n/a
|
||||
postcss-reporter MIT David Clark david.dave.clark@gmail.com https://davidtheclark.com
|
||||
postcss-url MIT Maxime Thirouin
|
||||
prettier MIT James Long
|
||||
pubsub-js MIT Morgan Roderick morgan@roderick.dk http://roderick.dk
|
||||
regenerator-runtime MIT Ben Newman <bn@cs.stanford.edu>
|
||||
resolve-url-loader MIT bholloway
|
||||
sanitize-html MIT Apostrophe Technologies, Inc.
|
||||
sass MIT Natalie Weizenbaum nweiz@google.com https://github.com/nex3
|
||||
sass-loader MIT J. Tangelder
|
||||
server MIT Francisco Presencia <public@francisco.io> (https://francisco.io/)
|
||||
sockette MIT Luke Edwards luke.edwards05@gmail.com lukeed.com
|
||||
standard MIT Feross Aboukhadijeh feross@feross.org https://feross.org
|
||||
style-loader MIT Tobias Koppers @sokra
|
||||
svg-url-loader MIT Hovhannes Babayan
|
||||
tar ISC Isaac Z. Schlueter
|
||||
url-loader MIT Tobias Koppers @sokra
|
||||
util MIT Joyent http://www.joyent.com
|
||||
vue MIT Evan You
|
||||
vue-3-sanitize MIT Vannsl, Vanessa Otto <mail@vannsl.io>
|
||||
vue-loader MIT Evan You
|
||||
vue-loader-plugin ISC Ivan liu
|
||||
vue-luxon MIT Cas Bloem
|
||||
vue-router MIT Eduardo San Martin Morote posva13@gmail.com
|
||||
vue-sanitize-directive MIT Leonardo Piccioni de Almeida leopiccionia@gmail.com
|
||||
vue-style-loader MIT Evan You
|
||||
vue3-gettext MIT Leo Zurbriggen
|
||||
vuetify MIT John Leider john@vuetifyjs.com
|
||||
webpack MIT Tobias Koppers @sokra
|
||||
webpack-bundle-analyzer MIT Yury Grunin <grunin.ya@ya.ru>
|
||||
webpack-cli MIT n/a
|
||||
webpack-hot-middleware MIT Glen Mailer <glen@stainlessed.co.uk>
|
||||
webpack-manifest-plugin MIT Dane Thurber <dane.thurber@gmail.com>
|
||||
webpack-md5-hash MIT Kirill Ermolov
|
||||
webpack-merge MIT Juho Vepsalainen <bebraw@gmail.com>
|
||||
webpack-plugin-vuetify MIT Kael Watts-Deuchar
|
||||
Package License Copyright
|
||||
------- ------- ---------
|
||||
@babel/cli MIT The Babel Team (https://babel.dev/team)
|
||||
@babel/core MIT The Babel Team (https://babel.dev/team)
|
||||
@babel/plugin-transform-runtime MIT The Babel Team (https://babel.dev/team)
|
||||
@babel/preset-env MIT The Babel Team (https://babel.dev/team)
|
||||
@babel/register MIT The Babel Team (https://babel.dev/team)
|
||||
@babel/runtime MIT The Babel Team (https://babel.dev/team)
|
||||
@eslint/eslintrc MIT Nicholas C. Zakas
|
||||
@eslint/js MIT n/a
|
||||
@lcdp/offline-plugin MIT Le Comptoir Des Pharmacies <webmaster@lecomptoirdespharmacies.fr>
|
||||
@mdi/font Apache-2.0 Austin Andrews
|
||||
@testing-library/jest-dom MIT Ernesto Garcia <gnapse@gmail.com> (http://gnapse.github.io)
|
||||
@testing-library/react MIT Kent C. Dodds <me@kentcdodds.com> (https://kentcdodds.com)
|
||||
@vitejs/plugin-react MIT Evan You
|
||||
@vitejs/plugin-vue MIT Evan You
|
||||
@vitest/browser MIT n/a
|
||||
@vitest/coverage-v8 MIT Anthony Fu <anthonyfu117@hotmail.com>
|
||||
@vitest/ui MIT n/a
|
||||
@vue/compiler-sfc MIT Evan You
|
||||
@vue/language-server MIT n/a
|
||||
@vue/test-utils MIT Lachlan Miller lachlan.miller.1990@outlook.com
|
||||
@vvo/tzdb MIT Vincent Voyer <vincent@codeagain.com>
|
||||
axios MIT Matt Zabriskie
|
||||
axios-mock-adapter MIT Colin Timmermans <colintimmermans@gmail.com>
|
||||
babel-loader MIT Luis Couto <hello@luiscouto.pt>
|
||||
babel-plugin-istanbul BSD-3-Clause Thai Pangsakulyanont @dtinth
|
||||
babel-plugin-polyfill-corejs3 MIT n/a
|
||||
browserslist MIT Andrey Sitnik <andrey@sitnik.ru>
|
||||
cheerio MIT Matt Mueller <mattmuelle@gmail.com>
|
||||
core-js MIT Denis Pushkarev zloirock@zloirock.ru http://zloirock.ru
|
||||
cross-env MIT Kent C. Dodds <me@kentcdodds.com> (https://kentcdodds.com)
|
||||
css-loader MIT Tobias Koppers @sokra
|
||||
cssnano MIT Ben Briggs beneb.info@gmail.com http://beneb.info
|
||||
easygettext MIT Polyconseil
|
||||
eslint MIT Nicholas C. Zakas <nicholas+npm@nczconsulting.com>
|
||||
eslint-config-prettier MIT Simon Lydell
|
||||
eslint-formatter-pretty MIT Sindre Sorhus sindresorhus@gmail.com https://sindresorhus.com
|
||||
eslint-plugin-html ISC n/a
|
||||
eslint-plugin-import MIT Ben Mosher <me@benmosher.com>
|
||||
eslint-plugin-node MIT Toru Nagashima
|
||||
eslint-plugin-prettier MIT Teddy Katz
|
||||
eslint-plugin-vue MIT Toru Nagashima (https://github.com/mysticatea)
|
||||
eslint-plugin-vuetify MIT Kael Watts-Deuchar <kaelwd@gmail.com>
|
||||
eslint-webpack-plugin MIT Ricardo Gobbo de Souza <ricardogobbosouza@yahoo.com.br>
|
||||
eventsource-polyfill MIT amvtek <devel@amvtek.com>
|
||||
file-loader MIT Tobias Koppers @sokra
|
||||
file-saver MIT Eli Grey <me@eligrey.com>
|
||||
floating-vue MIT Guillaume Chau <guillaume.b.chau@gmail.com>
|
||||
globals MIT Sindre Sorhus sindresorhus@gmail.com https://sindresorhus.com
|
||||
hls.js Apache-2.0 n/a
|
||||
i MIT Pavan Kumar Sunkara <pavan.sss1991@gmail.com> (pksunkara.github.com)
|
||||
jsdom MIT n/a
|
||||
luxon MIT Isaac Cambron
|
||||
maplibre-gl BSD-3-Clause n/a
|
||||
memoize-one MIT Alex Reardon <alexreardon@gmail.com>
|
||||
mini-css-extract-plugin MIT Tobias Koppers @sokra
|
||||
minimist MIT James Halliday mail@substack.net http://substack.net
|
||||
node-storage-shim ISC Michael Nahkies
|
||||
passive-events-support MIT Ignas Damunskis <ignas3run@gmail.com>
|
||||
photoswipe MIT Dmytro Semenov (https://dimsemenov.com)
|
||||
playwright Apache-2.0 Microsoft Corporation
|
||||
postcss MIT Andrey Sitnik <andrey@sitnik.ru>
|
||||
postcss-import MIT Maxime Thirouin
|
||||
postcss-loader MIT Andrey Sitnik <andrey@sitnik.ru>
|
||||
postcss-preset-env MIT-0 n/a
|
||||
postcss-reporter MIT David Clark david.dave.clark@gmail.com https://davidtheclark.com
|
||||
postcss-url MIT Maxime Thirouin
|
||||
prettier MIT James Long
|
||||
pubsub-js MIT Morgan Roderick morgan@roderick.dk http://roderick.dk
|
||||
regenerator-runtime MIT Ben Newman <bn@cs.stanford.edu>
|
||||
resolve-url-loader MIT bholloway
|
||||
sanitize-html MIT Apostrophe Technologies, Inc.
|
||||
sass MIT Natalie Weizenbaum nweiz@google.com https://github.com/nex3
|
||||
sass-loader MIT J. Tangelder
|
||||
server MIT Francisco Presencia <public@francisco.io> (https://francisco.io/)
|
||||
sockette MIT Luke Edwards luke.edwards05@gmail.com lukeed.com
|
||||
style-loader MIT Tobias Koppers @sokra
|
||||
svg-url-loader MIT Hovhannes Babayan
|
||||
tar ISC Isaac Z. Schlueter
|
||||
url-loader MIT Tobias Koppers @sokra
|
||||
util MIT Joyent http://www.joyent.com
|
||||
vite-tsconfig-paths MIT aleclarson
|
||||
vitest MIT Anthony Fu <anthonyfu117@hotmail.com>
|
||||
vue MIT Evan You
|
||||
vue-3-sanitize MIT Vannsl, Vanessa Otto <mail@vannsl.io>
|
||||
vue-loader MIT Evan You
|
||||
vue-loader-plugin ISC Ivan liu
|
||||
vue-luxon MIT Cas Bloem
|
||||
vue-router MIT Eduardo San Martin Morote posva13@gmail.com
|
||||
vue-sanitize-directive MIT Leonardo Piccioni de Almeida leopiccionia@gmail.com
|
||||
vue-style-loader MIT Evan You
|
||||
vue3-gettext MIT Leo Zurbriggen
|
||||
vuetify MIT John Leider john@vuetifyjs.com
|
||||
webpack MIT Tobias Koppers @sokra
|
||||
webpack-bundle-analyzer MIT Yury Grunin <grunin.ya@ya.ru>
|
||||
webpack-cli MIT n/a
|
||||
webpack-hot-middleware MIT Glen Mailer <glen@stainlessed.co.uk>
|
||||
webpack-manifest-plugin MIT Dane Thurber <dane.thurber@gmail.com>
|
||||
webpack-md5-hash MIT Kirill Ermolov
|
||||
webpack-merge MIT Juho Vepsalainen <bebraw@gmail.com>
|
||||
webpack-plugin-vuetify MIT Kael Watts-Deuchar
|
||||
|
142
frontend/eslint.config.mjs
Normal file
142
frontend/eslint.config.mjs
Normal file
@@ -0,0 +1,142 @@
|
||||
import { defineConfig, globalIgnores } from "eslint/config";
|
||||
import globals from "globals";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import js from "@eslint/js";
|
||||
import { FlatCompat } from "@eslint/eslintrc";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const compat = new FlatCompat({
|
||||
baseDirectory: __dirname,
|
||||
recommendedConfig: js.configs.recommended,
|
||||
allConfig: js.configs.all,
|
||||
});
|
||||
|
||||
export default defineConfig([
|
||||
globalIgnores([
|
||||
"**/coverage/",
|
||||
"**/node_modules/",
|
||||
"tests/screenshots/",
|
||||
"tests/acceptance/screenshots/",
|
||||
"tests/upload-files/",
|
||||
"**/*.html",
|
||||
"**/.idea",
|
||||
"**/.codex",
|
||||
"**/.env",
|
||||
"**/.venv",
|
||||
"**/.github",
|
||||
"**/.tmp",
|
||||
"**/.local",
|
||||
"**/.cache",
|
||||
"**/.gocache",
|
||||
"**/.var",
|
||||
]),
|
||||
{
|
||||
extends: compat.extends(
|
||||
"eslint:recommended",
|
||||
"plugin:vue/recommended",
|
||||
"plugin:prettier/recommended",
|
||||
"plugin:vue/base",
|
||||
"plugin:vuetify/base"
|
||||
),
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.browser,
|
||||
...globals.commonjs,
|
||||
...globals.node,
|
||||
...globals.mocha,
|
||||
},
|
||||
|
||||
ecmaVersion: "latest",
|
||||
sourceType: "module",
|
||||
},
|
||||
settings: {
|
||||
"prettier/prettier": {
|
||||
// Settings for how to process Vue SFC Blocks
|
||||
SFCBlocks: {
|
||||
template: false,
|
||||
script: false,
|
||||
style: false,
|
||||
},
|
||||
|
||||
// Use prettierrc for prettier options or not (default: `true`)
|
||||
usePrettierrc: true,
|
||||
|
||||
// Set the options for `prettier.getFileInfo`.
|
||||
// @see https://prettier.io/docs/en/api.html#prettiergetfileinfofilepath-options
|
||||
fileInfoOptions: {
|
||||
// Path to ignore file (default: `'.prettierignore'`)
|
||||
// Notice that the ignore file is only used for this plugin
|
||||
ignorePath: ".testignore",
|
||||
|
||||
// Process the files in `node_modules` or not (default: `false`)
|
||||
withNodeModules: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
"indent": ["error", 2, { SwitchCase: 1 }],
|
||||
"linebreak-style": ["error", "unix"],
|
||||
"quotes": [
|
||||
"off",
|
||||
"double",
|
||||
{
|
||||
avoidEscape: true,
|
||||
allowTemplateLiterals: true,
|
||||
},
|
||||
],
|
||||
"semi": ["error", "always"],
|
||||
"no-unused-vars": ["warn"],
|
||||
"no-console": 0,
|
||||
"no-case-declarations": 0,
|
||||
"no-prototype-builtins": 0,
|
||||
"vue/no-v-text-v-html-on-component": 0,
|
||||
"vue/no-v-model-argument": 0,
|
||||
"vue/valid-model-definition": 0,
|
||||
"vue/valid-attribute-name": 0,
|
||||
"vue/singleline-html-element-content-newline": [
|
||||
"off",
|
||||
{
|
||||
ignoreWhenNoAttributes: true,
|
||||
ignoreWhenEmpty: true,
|
||||
ignores: [
|
||||
"pre",
|
||||
"textarea",
|
||||
"span",
|
||||
"translate",
|
||||
"a",
|
||||
"v-icon",
|
||||
"v-text-field",
|
||||
"v-input",
|
||||
"v-select",
|
||||
"v-switch",
|
||||
"v-checkbox",
|
||||
"v-img",
|
||||
],
|
||||
externalIgnores: [],
|
||||
},
|
||||
],
|
||||
"vue/first-attribute-linebreak": [
|
||||
"error",
|
||||
{
|
||||
singleline: "ignore",
|
||||
multiline: "ignore",
|
||||
},
|
||||
],
|
||||
"prettier/prettier": [
|
||||
"warn",
|
||||
{
|
||||
printWidth: 120,
|
||||
semi: true,
|
||||
singleQuote: false,
|
||||
bracketSpacing: true,
|
||||
trailingComma: "es5",
|
||||
htmlWhitespaceSensitivity: "css",
|
||||
quoteProps: "consistent",
|
||||
proseWrap: "never",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
]);
|
21
frontend/gettext.config.js
Normal file
21
frontend/gettext.config.js
Normal file
@@ -0,0 +1,21 @@
|
||||
const glob = require("glob");
|
||||
const path = require("path");
|
||||
const poPath = path.resolve(__dirname, "src/locales");
|
||||
|
||||
// Generates a list of existing locales based on the files in src/locales.
|
||||
const languageCodes = glob.sync(poPath + "/*.po").map((filePath) => {
|
||||
const fileName = path.basename(filePath);
|
||||
return fileName.replace(".po", "");
|
||||
});
|
||||
|
||||
// Generates one JSON file per locale from the gettext *.po files located in src/locales.
|
||||
module.exports = {
|
||||
output: {
|
||||
path: path.resolve(__dirname, "src/locales"),
|
||||
potPath: "src/locales/translations.pot",
|
||||
jsonPath: "json",
|
||||
locales: languageCodes,
|
||||
splitJson: true,
|
||||
flat: true,
|
||||
},
|
||||
};
|
@@ -168,4 +168,7 @@ module.exports = (config) => {
|
||||
|
||||
singleRun: true,
|
||||
});
|
||||
|
||||
// Set default timezone.
|
||||
process.env.TZ = "UTC";
|
||||
};
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user