Compare commits
497 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c560ec0f9f | ||
|
|
71554e0c85 | ||
|
|
0efd7c5718 | ||
|
|
901ad7529e | ||
|
|
b64bcc9738 | ||
|
|
fddb7b7584 | ||
|
|
b91302ddf8 | ||
|
|
ea0293bd4e | ||
|
|
51f2f4cc6a | ||
|
|
2d93b3b7ee | ||
|
|
0f41d1e6cf | ||
|
|
36edd4ab0d | ||
|
|
716d6a931a | ||
|
|
72bf280e2d | ||
|
|
326c2cf70a | ||
|
|
2816c6277d | ||
|
|
99875b9176 | ||
|
|
0e21942cd6 | ||
|
|
b2b5083102 | ||
|
|
c0f316d049 | ||
|
|
2c6d08319b | ||
|
|
5d8f139356 | ||
|
|
87ef71b415 | ||
|
|
cf99ae880c | ||
|
|
8e86078394 | ||
|
|
beea903879 | ||
|
|
c5e4c5d509 | ||
|
|
fac951c733 | ||
|
|
83449f3332 | ||
|
|
2a9fc8c7a5 | ||
|
|
f8d4f79271 | ||
|
|
bc466d0c6f | ||
|
|
382a0f4c3c | ||
|
|
488c2f5df5 | ||
|
|
43effd0c32 | ||
|
|
af61549bf1 | ||
|
|
22a0d8925d | ||
|
|
59a014f681 | ||
|
|
9944cc2db9 | ||
|
|
570e3a1e54 | ||
|
|
a9bde40661 | ||
|
|
b03a185e88 | ||
|
|
e450587eea | ||
|
|
30a529baac | ||
|
|
adbb74f56b | ||
|
|
223b4df172 | ||
|
|
44dc315914 | ||
|
|
c959e2ce4d | ||
|
|
57b10dd514 | ||
|
|
9da0f89613 | ||
|
|
4104cb334e | ||
|
|
94067a1ec2 | ||
|
|
3e9da3baf7 | ||
|
|
6129305b2c | ||
|
|
7165eb1f59 | ||
|
|
a4820de423 | ||
|
|
0c09f3b05f | ||
|
|
269d67f071 | ||
|
|
bdc0c0ffa2 | ||
|
|
c00f5f4330 | ||
|
|
a2c344de83 | ||
|
|
886ae64feb | ||
|
|
90a2c1f2e7 | ||
|
|
d772e43e44 | ||
|
|
8fdab39b18 | ||
|
|
f7d2771263 | ||
|
|
e8b1cca9ca | ||
|
|
d4d7219801 | ||
|
|
3273607fc3 | ||
|
|
55e21f8be3 | ||
|
|
dafb439a7d | ||
|
|
ab94de2f95 | ||
|
|
3dc0df0ac2 | ||
|
|
d701c5f27d | ||
|
|
a8f71c83da | ||
|
|
7a3e0d60f9 | ||
|
|
2687af31ca | ||
|
|
d51a6abb02 | ||
|
|
374ffbf01f | ||
|
|
871bc9f396 | ||
|
|
66b7df7cde | ||
|
|
bc76770ca4 | ||
|
|
7196361cf6 | ||
|
|
3e73d16cce | ||
|
|
3f8414c70a | ||
|
|
6ec2186bdf | ||
|
|
6dd575b276 | ||
|
|
1a98946d71 | ||
|
|
8922549bdb | ||
|
|
173b49aeb7 | ||
|
|
eee6046465 | ||
|
|
b76011be4f | ||
|
|
3d93d79b0b | ||
|
|
7dcc9b20a1 | ||
|
|
754b956206 | ||
|
|
47ac505cac | ||
|
|
e6e5231f63 | ||
|
|
78049d4a33 | ||
|
|
8a6cfe0b4d | ||
|
|
afedc78113 | ||
|
|
76b822213e | ||
|
|
ab3d5f3321 | ||
|
|
e1d42c8a87 | ||
|
|
f53c852a4d | ||
|
|
aaea889e47 | ||
|
|
bf98c74ecf | ||
|
|
fcadabd339 | ||
|
|
2a0edeb3c5 | ||
|
|
30f16e7207 | ||
|
|
dbe7e2e659 | ||
|
|
e16f05b130 | ||
|
|
07573a515a | ||
|
|
b3a2de50cf | ||
|
|
5388d3d4c0 | ||
|
|
c392d48174 | ||
|
|
967fab3411 | ||
|
|
d7845b78f6 | ||
|
|
a253858625 | ||
|
|
ad1aae16e3 | ||
|
|
9370913ace | ||
|
|
dcd2e234e8 | ||
|
|
762dac2581 | ||
|
|
1cf8d3037b | ||
|
|
40808bdcb9 | ||
|
|
2451d69341 | ||
|
|
e449853568 | ||
|
|
2082e960c2 | ||
|
|
7b2a083f98 | ||
|
|
270143a8f6 | ||
|
|
766b69d95e | ||
|
|
f5addc4947 | ||
|
|
55eb59c526 | ||
|
|
679cac4dbd | ||
|
|
a0a25d64f1 | ||
|
|
9875458b01 | ||
|
|
f0dccc58aa | ||
|
|
636bc22d52 | ||
|
|
fc6b6a9c6b | ||
|
|
1a6d78352c | ||
|
|
e351c35cc8 | ||
|
|
618cc32a17 | ||
|
|
a8bf670697 | ||
|
|
0bdf8ad6ce | ||
|
|
8f65e2e968 | ||
|
|
0d3f96c3a7 | ||
|
|
cfa7947020 | ||
|
|
b91de3f319 | ||
|
|
1704ae8cb1 | ||
|
|
50c6e6031d | ||
|
|
de92516d52 | ||
|
|
cd67d3e7ab | ||
|
|
c556878f11 | ||
|
|
3af4607171 | ||
|
|
111533fa2d | ||
|
|
5dc0a68b44 | ||
|
|
43e5bbbe21 | ||
|
|
42921f6a3e | ||
|
|
5892899114 | ||
|
|
4404c84e7f | ||
|
|
a86be55b5c | ||
|
|
5eea72a579 | ||
|
|
03247ddef8 | ||
|
|
e6e5b0f3cf | ||
|
|
9b977bafbf | ||
|
|
77f755e43c | ||
|
|
30bef15855 | ||
|
|
7bd8fadf76 | ||
|
|
21490faa9e | ||
|
|
f685582e1a | ||
|
|
f792166523 | ||
|
|
7c0754a70c | ||
|
|
2f33580f32 | ||
|
|
eb8f2777ae | ||
|
|
92332206f0 | ||
|
|
9787fce275 | ||
|
|
1c67b06c27 | ||
|
|
88eab75e30 | ||
|
|
6c5f776a7a | ||
|
|
ca0c56e748 | ||
|
|
e29e0ddb5b | ||
|
|
7ce75c271c | ||
|
|
884493e7aa | ||
|
|
bd05a4b35a | ||
|
|
fa7da1b23f | ||
|
|
1ec5d2ca3f | ||
|
|
1e9d184508 | ||
|
|
2934832a98 | ||
|
|
3635b6a367 | ||
|
|
2b97850eb2 | ||
|
|
c1d1b0e560 | ||
|
|
e1d9a00d67 | ||
|
|
35aa37e10e | ||
|
|
e38c470fb9 | ||
|
|
edd4584136 | ||
|
|
d7a84c1982 | ||
|
|
fe86b8a7d0 | ||
|
|
01f290b459 | ||
|
|
9a398e9291 | ||
|
|
1fbd11dbe8 | ||
|
|
68b26f8301 | ||
|
|
6877f3975e | ||
|
|
6a11ed5622 | ||
|
|
53bec00a7e | ||
|
|
c616ab324d | ||
|
|
7e21eb87db | ||
|
|
98cd33da05 | ||
|
|
d520694e12 | ||
|
|
3c4800efa8 | ||
|
|
bd227842d2 | ||
|
|
f47bf762ac | ||
|
|
1342208980 | ||
|
|
c8a9b15b4e | ||
|
|
b0bd6973d1 | ||
|
|
d10eb6d6bf | ||
|
|
0c5a332fa2 | ||
|
|
5a07e103c0 | ||
|
|
40fc5e9604 | ||
|
|
9799665951 | ||
|
|
b3fa667db1 | ||
|
|
027cf19d0f | ||
|
|
38119551d7 | ||
|
|
52d9cda61a | ||
|
|
f40fb9d3f7 | ||
|
|
9536ceaaa4 | ||
|
|
72beee1322 | ||
|
|
0ec822988d | ||
|
|
d1b1b90de3 | ||
|
|
058cac2e7b | ||
|
|
6ffdd4dad7 | ||
|
|
98d59ba4e0 | ||
|
|
938523c18b | ||
|
|
cc4e12c405 | ||
|
|
eb406ef951 | ||
|
|
5c87d109a3 | ||
|
|
3e020da66a | ||
|
|
78157f763f | ||
|
|
bcc0eeeb2f | ||
|
|
76b859f5bf | ||
|
|
676cf619d5 | ||
|
|
ce45bf2136 | ||
|
|
b25f786018 | ||
|
|
ca00796077 | ||
|
|
a1bbf13d6a | ||
|
|
76fa171575 | ||
|
|
ce30537ebd | ||
|
|
93b5b483cc | ||
|
|
27ef931670 | ||
|
|
fb727e75ec | ||
|
|
fa433c88a8 | ||
|
|
adbb5b9d38 | ||
|
|
cdc837e781 | ||
|
|
a92baa5d18 | ||
|
|
e913f25a47 | ||
|
|
9eb803388e | ||
|
|
eb81515f46 | ||
|
|
52461c0356 | ||
|
|
6b3800abf6 | ||
|
|
09fc81d7f4 | ||
|
|
82034a2586 | ||
|
|
5e001bed60 | ||
|
|
5d7972db56 | ||
|
|
403ad58274 | ||
|
|
a1a233e74f | ||
|
|
8dd72c95ab | ||
|
|
f794322392 | ||
|
|
afd52d1d37 | ||
|
|
ba7370171a | ||
|
|
deb364a8bd | ||
|
|
a3cf498e15 | ||
|
|
3b356d2d8c | ||
|
|
20e17b576a | ||
|
|
8e680ff576 | ||
|
|
29d26aeb15 | ||
|
|
33b7876826 | ||
|
|
0fc4b5eb22 | ||
|
|
e672f9f14c | ||
|
|
4d2e509950 | ||
|
|
a80e5c2aa9 | ||
|
|
cd375208ba | ||
|
|
316f482bf5 | ||
|
|
0f78390282 | ||
|
|
0b909fc02d | ||
|
|
d4c6561abd | ||
|
|
1f5e6537a5 | ||
|
|
97f2ae34ca | ||
|
|
d193afbeca | ||
|
|
abea430b6b | ||
|
|
00cec2b157 | ||
|
|
41ff0be839 | ||
|
|
25330533bd | ||
|
|
4afd1bd4b5 | ||
|
|
cf185efdfc | ||
|
|
4ec9756f58 | ||
|
|
cda7db5718 | ||
|
|
3b37fb5692 | ||
|
|
40c83803de | ||
|
|
a9811c164e | ||
|
|
8f000876b3 | ||
|
|
0af393236f | ||
|
|
3153c65f5a | ||
|
|
6ce825bd41 | ||
|
|
060f0efc16 | ||
|
|
c3fb00a307 | ||
|
|
988829a6db | ||
|
|
76935a300a | ||
|
|
a6a7710a79 | ||
|
|
873afb47cd | ||
|
|
ea99966057 | ||
|
|
aaed272bf2 | ||
|
|
e6775cd2d1 | ||
|
|
98a9e20cc0 | ||
|
|
ee37588959 | ||
|
|
cb12c6f441 | ||
|
|
72cf3e2240 | ||
|
|
815bdc35ac | ||
|
|
0330540f87 | ||
|
|
fefe2d82a4 | ||
|
|
1af8d1f77d | ||
|
|
4c653fea36 | ||
|
|
2ee0ed55f6 | ||
|
|
94981f4891 | ||
|
|
f72def0399 | ||
|
|
81fb0fc69f | ||
|
|
c3af0f4380 | ||
|
|
3a9e4950d4 | ||
|
|
06dada297b | ||
|
|
2b55a1873c | ||
|
|
c2e68bdc77 | ||
|
|
e1c3b312ff | ||
|
|
e235ed9fda | ||
|
|
5cda12dd3b | ||
|
|
a9d48083fd | ||
|
|
e28c50401e | ||
|
|
4a3b015a40 | ||
|
|
1a6727312c | ||
|
|
91d3d2596e | ||
|
|
192c9a4764 | ||
|
|
173c38563e | ||
|
|
d061721f56 | ||
|
|
218882b7c6 | ||
|
|
fed3ee4c4f | ||
|
|
8eed4b0127 | ||
|
|
c09ffb49e7 | ||
|
|
f331f4eb92 | ||
|
|
629b669c64 | ||
|
|
2dab900748 | ||
|
|
f864097f2e | ||
|
|
2c8be42bbc | ||
|
|
6691ae27f4 | ||
|
|
23fecb16b2 | ||
|
|
b037b08152 | ||
|
|
46fe3a7f5d | ||
|
|
61bd62403f | ||
|
|
5893d4b855 | ||
|
|
8016e6f211 | ||
|
|
a5560b04bd | ||
|
|
b9e171b1fd | ||
|
|
a633425baa | ||
|
|
e29e89c618 | ||
|
|
62c986161c | ||
|
|
6279c73402 | ||
|
|
22e103837f | ||
|
|
feba6e7bae | ||
|
|
95a6b48c3e | ||
|
|
90c6cee780 | ||
|
|
456ef556b1 | ||
|
|
ce98b2eb5a | ||
|
|
ee026714d4 | ||
|
|
736c39840f | ||
|
|
e755bc6b61 | ||
|
|
7ec9f2435c | ||
|
|
443d6fee52 | ||
|
|
b023616033 | ||
|
|
f182b88c58 | ||
|
|
93daadae4b | ||
|
|
fd1ec5d3fb | ||
|
|
b9a8a27807 | ||
|
|
27a36898a3 | ||
|
|
d8948c037b | ||
|
|
83f2749eab | ||
|
|
290435b5ba | ||
|
|
d09125c63c | ||
|
|
f0aa64373b | ||
|
|
2272883d5a | ||
|
|
2d0f6d89aa | ||
|
|
4cd1571c05 | ||
|
|
55be62bc3e | ||
|
|
da82f1c146 | ||
|
|
67f53d4112 | ||
|
|
88356281fb | ||
|
|
05198ea764 | ||
|
|
fe33d97d87 | ||
|
|
2c60dee48a | ||
|
|
8af9f9944a | ||
|
|
4e968d2338 | ||
|
|
7ba88977a4 | ||
|
|
0c5f6a68f9 | ||
|
|
bbd539278c | ||
|
|
be9d9ac6ff | ||
|
|
e8b37a5df8 | ||
|
|
d10d347e2b | ||
|
|
68689d74a0 | ||
|
|
4fc9bdb35b | ||
|
|
c0a05be44e | ||
|
|
482c9d5719 | ||
|
|
f063298bf7 | ||
|
|
bb1e454850 | ||
|
|
11770d90f1 | ||
|
|
8a415140b6 | ||
|
|
3dd83bffbf | ||
|
|
79987ffa22 | ||
|
|
764639bbba | ||
|
|
eb67116ee6 | ||
|
|
7baea9101e | ||
|
|
167fae9892 | ||
|
|
c7f5aa2e2b | ||
|
|
8c871bc5fa | ||
|
|
1f6bbc75ff | ||
|
|
23ae18d732 | ||
|
|
bf1e6230dc | ||
|
|
8af1c13d7e | ||
|
|
061945218a | ||
|
|
687edf2b0b | ||
|
|
1bf1e994fe | ||
|
|
7f91a27e4f | ||
|
|
f66510c74b | ||
|
|
e5de8b20ff | ||
|
|
dd96d71280 | ||
|
|
a687b2c438 | ||
|
|
ea262ca60b | ||
|
|
406fef6595 | ||
|
|
f7d8feac5d | ||
|
|
cd2ea2e579 | ||
|
|
b66654787c | ||
|
|
882a3467db | ||
|
|
27ac0bf43e | ||
|
|
4485622354 | ||
|
|
91b2b44768 | ||
|
|
8c276fa0a7 | ||
|
|
78b0e22091 | ||
|
|
96abbdf9a8 | ||
|
|
7c61392ff4 | ||
|
|
901abfb3e5 | ||
|
|
2eea836d9f | ||
|
|
9a08a6603a | ||
|
|
887126f5dd | ||
|
|
fad6a04a5f | ||
|
|
e834445b0b | ||
|
|
1aadd12006 | ||
|
|
26a1f30d32 | ||
|
|
e0a17c6a74 | ||
|
|
7ce1b5001c | ||
|
|
72a7759ca5 | ||
|
|
bf46c9f906 | ||
|
|
14bb85f301 | ||
|
|
e68dccbc17 | ||
|
|
ffc62574ec | ||
|
|
ca0889aaab | ||
|
|
772e12d11c | ||
|
|
7d04487b18 | ||
|
|
0b482116bb | ||
|
|
a579bcd463 | ||
|
|
ab7017ff12 | ||
|
|
3d5bea003a | ||
|
|
bc99dc34ee | ||
|
|
965c449f1c | ||
|
|
4679c6f355 | ||
|
|
a3351f4da8 | ||
|
|
422f13202b | ||
|
|
c470e40737 | ||
|
|
0f92ce2166 | ||
|
|
b1becb9ef5 | ||
|
|
3c1599b6b7 | ||
|
|
3e53b742f4 | ||
|
|
5401593279 | ||
|
|
0710e05479 | ||
|
|
1707d011a2 | ||
|
|
5e8d7944bd | ||
|
|
2d2727f7e8 | ||
|
|
c72282613d | ||
|
|
4ac62a107c | ||
|
|
a102199d5a | ||
|
|
3c799b8783 | ||
|
|
3fbbc7f620 | ||
|
|
461efa7f60 | ||
|
|
1321f8df50 | ||
|
|
a081f3a799 | ||
|
|
e532000ad0 | ||
|
|
8d0dc232d7 | ||
|
|
f5602f1e96 | ||
|
|
d9e1e2f58b | ||
|
|
5d56ed5378 | ||
|
|
4aae655180 | ||
|
|
6860933498 | ||
|
|
377c8d3e4e | ||
|
|
74bbfdf5c2 | ||
|
|
0171fb8569 |
136
.drone.yml
@@ -11,17 +11,59 @@ steps:
|
||||
- name: release
|
||||
image: golang:latest
|
||||
environment:
|
||||
BUILDRONE_KEY:
|
||||
from_secret: BUILDRONE_KEY
|
||||
GITHUB_TOKEN:
|
||||
from_secret: github_token
|
||||
commands:
|
||||
- apt update -y
|
||||
- apt install build-essential python3-pip curl software-properties-common sed upx -y
|
||||
- apt-get update -y
|
||||
- apt-get install build-essential python3-pip curl software-properties-common sed upx -y
|
||||
- (curl -sL https://deb.nodesource.com/setup_14.x | bash -)
|
||||
- apt install nodejs
|
||||
- curl -sL https://git.io/goreleaser | bash
|
||||
when:
|
||||
event: tag
|
||||
- apt-get install nodejs
|
||||
- curl -sL https://git.io/goreleaser > ../goreleaser
|
||||
- chmod +x ../goreleaser
|
||||
- ./scripts/version.sh ../goreleaser
|
||||
- wget https://builds.hrfee.pw/upload.py -P ../
|
||||
- pip3 install requests
|
||||
- bash -c 'python3 ../upload.py https://builds.hrfee.pw hrfee jfa-go --tag internal=true'
|
||||
trigger:
|
||||
event:
|
||||
- tag
|
||||
---
|
||||
name: docker-buildx
|
||||
kind: pipeline
|
||||
type: docker
|
||||
|
||||
steps:
|
||||
- name: build-deploy
|
||||
image: appleboy/drone-ssh
|
||||
volumes:
|
||||
- name: ssh_key
|
||||
path: /root/drone_rsa
|
||||
settings:
|
||||
host:
|
||||
from_secret: ssh2_host
|
||||
username:
|
||||
from_secret: ssh2_username
|
||||
port:
|
||||
from_secret: ssh2_port
|
||||
volumes:
|
||||
- /root/.ssh/docker-build:/root/drone_rsa
|
||||
key_path: /root/drone_rsa
|
||||
command_timeout: 50m
|
||||
script:
|
||||
- /mnt/buildx/jfa-go/build.sh stable
|
||||
- wget https://builds.hrfee.pw/upload.py -O /mnt/buildx/jfa-go/jfa-go/upload.py
|
||||
- pip3 install requests
|
||||
- bash -c 'cd /mnt/buildx/jfa-go/jfa-go && BUILDRONE_KEY=$(cat /mnt/buildx/jfa-go/key) python3 upload.py https://builds.hrfee.pw hrfee jfa-go --tag docker-stable=true'
|
||||
- rm -f /mnt/buildx/jfa-go/jfa-go/upload.py
|
||||
trigger:
|
||||
event:
|
||||
- tag
|
||||
volumes:
|
||||
- name: ssh_key
|
||||
host:
|
||||
path: /root/.ssh/docker-build
|
||||
---
|
||||
name: jfa-go-git
|
||||
kind: pipeline
|
||||
@@ -31,17 +73,85 @@ steps:
|
||||
- name: build
|
||||
image: golang:latest
|
||||
commands:
|
||||
- apt update -y
|
||||
- apt install build-essential python3-pip curl software-properties-common sed upx -y
|
||||
- apt-get update -y
|
||||
- apt-get install build-essential python3-pip curl software-properties-common sed upx -y
|
||||
- (curl -sL https://deb.nodesource.com/setup_14.x | bash -)
|
||||
- apt install nodejs
|
||||
- curl -sL https://git.io/goreleaser > goreleaser.sh
|
||||
- chmod +x goreleaser.sh
|
||||
- ./goreleaser.sh --snapshot --skip-publish --rm-dist
|
||||
- apt-get install nodejs
|
||||
- curl -sL https://git.io/goreleaser > goreleaser
|
||||
- chmod +x goreleaser
|
||||
- ./scripts/version.sh ./goreleaser --snapshot --skip-publish --rm-dist
|
||||
- wget https://builds.hrfee.pw/upload.py
|
||||
- pip3 install requests
|
||||
- bash -c 'python3 upload.py https://builds.hrfee.pw hrfee jfa-go ./dist/*.tar.gz'
|
||||
- bash -c 'python3 upload.py https://builds.hrfee.pw hrfee jfa-go --upload ./dist/*.tar.gz --tag internal-git=true'
|
||||
environment:
|
||||
BUILDRONE_KEY:
|
||||
from_secret: BUILDRONE_KEY
|
||||
|
||||
trigger:
|
||||
branch:
|
||||
- main
|
||||
- go1.16
|
||||
event:
|
||||
exclude:
|
||||
- pull_request
|
||||
|
||||
---
|
||||
name: docker-buildx-unstable
|
||||
kind: pipeline
|
||||
type: docker
|
||||
|
||||
steps:
|
||||
- name: build-deploy
|
||||
image: appleboy/drone-ssh
|
||||
volumes:
|
||||
- name: ssh_key
|
||||
path: /root/drone_rsa
|
||||
settings:
|
||||
host:
|
||||
from_secret: ssh2_host
|
||||
username:
|
||||
from_secret: ssh2_username
|
||||
port:
|
||||
from_secret: ssh2_port
|
||||
volumes:
|
||||
- /root/.ssh/docker-build:/root/drone_rsa
|
||||
key_path: /root/drone_rsa
|
||||
command_timeout: 50m
|
||||
script:
|
||||
- /mnt/buildx/jfa-go/build.sh
|
||||
- wget https://builds.hrfee.pw/upload.py -O /mnt/buildx/jfa-go/jfa-go/upload.py
|
||||
- pip3 install requests
|
||||
- bash -c 'cd /mnt/buildx/jfa-go/jfa-go && BUILDRONE_KEY=$(cat /mnt/buildx/jfa-go/key) python3 upload.py https://builds.hrfee.pw hrfee jfa-go --tag docker-unstable=true'
|
||||
- rm -f /mnt/buildx/jfa-go/jfa-go/upload.py
|
||||
trigger:
|
||||
branch:
|
||||
- main
|
||||
event:
|
||||
exclude:
|
||||
- pull_request
|
||||
|
||||
volumes:
|
||||
- name: ssh_key
|
||||
host:
|
||||
path: /root/.ssh/docker-build
|
||||
---
|
||||
name: jfa-go-pr
|
||||
kind: pipeline
|
||||
type: docker
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
image: golang:latest
|
||||
commands:
|
||||
- apt-get update -y
|
||||
- apt-get install build-essential python3-pip curl software-properties-common sed upx -y
|
||||
- (curl -sL https://deb.nodesource.com/setup_14.x | bash -)
|
||||
- apt-get install nodejs
|
||||
- curl -sL https://git.io/goreleaser > goreleaser
|
||||
- chmod +x goreleaser
|
||||
- ./scripts/version.sh ./goreleaser --snapshot --skip-publish --rm-dist
|
||||
|
||||
trigger:
|
||||
event:
|
||||
include:
|
||||
- pull_request
|
||||
|
||||
3
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
github: hrfee
|
||||
ko_fi: hrfee
|
||||
custom: https://www.buymeacoffee.com/hrfee
|
||||
7
.gitignore
vendored
@@ -6,5 +6,12 @@ data/
|
||||
version.go
|
||||
notes
|
||||
docs/*
|
||||
lang/langtostruct.py
|
||||
config-payload.json
|
||||
!docs/go.mod
|
||||
server.key
|
||||
server.pem
|
||||
server.crt
|
||||
instructions-debian.txt
|
||||
cl.md
|
||||
./telegram/
|
||||
|
||||
@@ -10,23 +10,29 @@ before:
|
||||
- rm -rf data/web
|
||||
- mkdir -p data
|
||||
- cp -r static data/web
|
||||
- cp -r css data/web/
|
||||
- npm install
|
||||
- cp node_modules/a17t/dist/a17t.css data/web/css/
|
||||
- npm install esbuild
|
||||
- mkdir -p data/web/css
|
||||
- npx esbuild --bundle css/base.css --outfile=./data/web/css/bundle.css --external:remixicon.css --minify
|
||||
- cp node_modules/remixicon/fonts/remixicon.css node_modules/remixicon/fonts/remixicon.woff2 data/web/css/
|
||||
- cp -r html data/
|
||||
- cp -r lang data/
|
||||
- python3 config/fixconfig.py -i config/config-base.json -o data/config-base.json
|
||||
- python3 config/generate_ini.py -i config/config-base.json -o data/config-default.ini
|
||||
- python3 mail/generate.py -o data/
|
||||
- python3 version.py {{.Version}} version.go
|
||||
- bash -c 'npx esbuild ts/*.ts ts/modules/*.ts --outdir=./data/web/js/ --minify'
|
||||
- cp LICENSE data/
|
||||
- python3 scripts/enumerate_config.py -i config/config-base.json -o data/config-base.json
|
||||
- python3 scripts/generate_ini.py -i config/config-base.json -o data/config-default.ini
|
||||
- python3 scripts/compile_mjml.py -o data/
|
||||
- npx esbuild --bundle ts/admin.ts --outfile=./data/web/js/admin.js --minify
|
||||
- npx esbuild --bundle ts/pwr.ts --outfile=./data/web/js/pwr.js --minify
|
||||
- npx esbuild --bundle ts/form.ts --outfile=./data/web/js/form.js --minify
|
||||
- npx esbuild --bundle ts/setup.ts --outfile=./data/web/js/setup.js --minify
|
||||
- go get -u github.com/swaggo/swag/cmd/swag
|
||||
- swag init -g main.go
|
||||
builds:
|
||||
- dir: ./
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
ldflags:
|
||||
- -s -w -X main.version={{.Env.JFA_GO_VERSION}} -X main.commit={{.ShortCommit}} -X main.updater=binary
|
||||
goos:
|
||||
- linux
|
||||
- windows
|
||||
@@ -37,14 +43,10 @@ builds:
|
||||
- arm64
|
||||
archives:
|
||||
- replacements:
|
||||
darwin: Darwin
|
||||
darwin: macOS
|
||||
linux: Linux
|
||||
windows: Windows
|
||||
amd64: x86_64
|
||||
files:
|
||||
- data/*
|
||||
- data/**/*
|
||||
- data/**/**/*
|
||||
checksum:
|
||||
name_template: 'checksums.txt'
|
||||
snapshot:
|
||||
|
||||
15
CONTRIBUTING.md
Normal file
@@ -0,0 +1,15 @@
|
||||
#### Code
|
||||
I use 4 spaces for indentation. Go should ideally be formatted with `goimports` and/or `gofmt`. I don't use a formatter on typescript, so don't worry about that.
|
||||
|
||||
#### Compiling
|
||||
|
||||
Prefix each of these with `make DEBUG=on INTERNAL=off `:
|
||||
* `all` will download deps and build everything. The executable and data will be placed in `build`. This is only necessary the first time.
|
||||
* `compile` will only compile go code into the `build/jfa-go` executable.
|
||||
* `typescript` will compile typescript w/ sourcemaps into `build/data/web/js`.
|
||||
* `bundle-css` will bundle CSS and place it in `build/data/web/css`.
|
||||
* `configuration` will generate the `config-base.json` (used to render settings in the web ui) and `config-default.ini` and put them in `build/data`.
|
||||
* `email` will compile email mjml, and copy the text versions in to `build/data`.
|
||||
* `copy` will copy iconography, html, language files and static data into `build/data`.
|
||||
|
||||
See the [wiki](https://github.com/hrfee/jfa-go/wiki/Build) for more info.
|
||||
22
Dockerfile
@@ -1,19 +1,29 @@
|
||||
FROM golang:latest AS build
|
||||
FROM --platform=$BUILDPLATFORM golang:latest AS support
|
||||
|
||||
COPY . /opt/build
|
||||
|
||||
RUN apt update -y \
|
||||
&& apt install build-essential python3-pip curl software-properties-common sed upx -y \
|
||||
RUN apt-get update -y \
|
||||
&& apt-get install build-essential python3-pip curl software-properties-common sed -y \
|
||||
&& (curl -sL https://deb.nodesource.com/setup_14.x | bash -) \
|
||||
&& apt install nodejs \
|
||||
&& (cd /opt/build; make all; make compress) \
|
||||
&& sed -i 's#id="pwrJfPath" placeholder="Folder"#id="pwrJfPath" value="/jf" disabled#g' /opt/build/build/data/html/setup.html
|
||||
&& apt-get install nodejs \
|
||||
&& (cd /opt/build; make configuration npm email typescript bundle-css swagger copy INTERNAL=off GOESBUILD=on) \
|
||||
&& sed -i 's#id="password_resets-watch_directory" placeholder="/config/jellyfin"#id="password_resets-watch_directory" value="/jf" disabled#g' /opt/build/build/data/html/setup.html
|
||||
|
||||
|
||||
FROM --platform=$BUILDPLATFORM golang:latest AS build
|
||||
ARG TARGETARCH
|
||||
ENV GOARCH=$TARGETARCH
|
||||
|
||||
COPY --from=support /opt/build /opt/build
|
||||
|
||||
RUN (cd /opt/build; make compile INTERNAL=off UPDATER=docker)
|
||||
|
||||
FROM golang:latest
|
||||
|
||||
COPY --from=build /opt/build/build /opt/jfa-go
|
||||
|
||||
EXPOSE 8056
|
||||
EXPOSE 8057
|
||||
|
||||
CMD [ "/opt/jfa-go/jfa-go", "-data", "/data" ]
|
||||
|
||||
|
||||
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Harvey Tindall
|
||||
Copyright (c) 2021 Harvey Tindall
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
130
Makefile
@@ -1,65 +1,125 @@
|
||||
GOESBUILD ?= off
|
||||
ifeq ($(GOESBUILD), on)
|
||||
ESBUILD := esbuild
|
||||
else
|
||||
ESBUILD := npx esbuild
|
||||
endif
|
||||
GOBINARY ?= go
|
||||
|
||||
VERSION ?= $(shell git describe --exact-match HEAD 2> /dev/null || echo vgit)
|
||||
VERSION := $(shell echo $(VERSION) | sed 's/v//g')
|
||||
COMMIT ?= $(shell git rev-parse --short HEAD || echo unknown)
|
||||
|
||||
UPDATER ?= off
|
||||
LDFLAGS := -X main.version=$(VERSION) -X main.commit=$(COMMIT)
|
||||
ifeq ($(UPDATER), on)
|
||||
LDFLAGS := $(LDFLAGS) -X main.updater=binary
|
||||
else ifneq ($(UPDATER), off)
|
||||
LDFLAGS := $(LDFLAGS) -X main.updater=$(UPDATER)
|
||||
endif
|
||||
|
||||
INTERNAL ?= on
|
||||
ifeq ($(INTERNAL), on)
|
||||
TAGS :=
|
||||
DATA := data
|
||||
else
|
||||
DATA := build/data
|
||||
TAGS := -tags external
|
||||
endif
|
||||
|
||||
DEBUG ?= off
|
||||
ifeq ($(DEBUG), on)
|
||||
LDFLAGS := -s -w $(LDFLAGS)
|
||||
SOURCEMAP := --sourcemap
|
||||
TYPECHECK := tsc -noEmit --project ts/tsconfig.json
|
||||
# jank
|
||||
COPYTS := rm -r $(DATA)/web/js/ts; cp -r ts $(DATA)/web/js
|
||||
else
|
||||
SOURCEMAP :=
|
||||
COPYTS :=
|
||||
TYPECHECK :=
|
||||
endif
|
||||
|
||||
npm:
|
||||
$(info installing npm dependencies)
|
||||
npm install
|
||||
@if [ "$(GOESBUILD)" = "off" ]; then\
|
||||
npm install esbuild;\
|
||||
else\
|
||||
go get -u github.com/evanw/esbuild/cmd/esbuild;\
|
||||
fi
|
||||
|
||||
configuration:
|
||||
$(info Fixing config-base)
|
||||
-mkdir -p build/data
|
||||
python3 config/fixconfig.py -i config/config-base.json -o build/data/config-base.json
|
||||
-mkdir -p $(DATA)
|
||||
python3 scripts/enumerate_config.py -i config/config-base.json -o $(DATA)/config-base.json
|
||||
$(info Generating config-default.ini)
|
||||
python3 config/generate_ini.py -i config/config-base.json -o build/data/config-default.ini
|
||||
python3 scripts/generate_ini.py -i config/config-base.json -o $(DATA)/config-default.ini
|
||||
|
||||
email:
|
||||
$(info Generating email html)
|
||||
python3 mail/generate.py -o build/data/
|
||||
python3 scripts/compile_mjml.py -o $(DATA)/
|
||||
|
||||
typescript:
|
||||
$(TYPECHECK)
|
||||
$(info compiling typescript)
|
||||
-mkdir -p build/data/web/js
|
||||
-npx esbuild ts/*.ts ts/modules/*.ts --outdir=./build/data/web/js/
|
||||
|
||||
ts-debug:
|
||||
$(info compiling typescript w/ sourcemaps)
|
||||
-mkdir -p build/data/web/js
|
||||
-npx esbuild ts/*.ts ts/modules/*.ts --sourcemap --outdir=./build/data/web/js/
|
||||
-rm -r build/data/web/js/ts
|
||||
$(info copying typescript)
|
||||
cp -r ts build/data/web/js
|
||||
-mkdir -p $(DATA)/web/js
|
||||
-$(ESBUILD) --bundle ts/admin.ts $(SOURCEMAP) --outfile=./$(DATA)/web/js/admin.js --minify
|
||||
-$(ESBUILD) --bundle ts/pwr.ts $(SOURCEMAP) --outfile=./$(DATA)/web/js/pwr.js --minify
|
||||
-$(ESBUILD) --bundle ts/form.ts $(SOURCEMAP) --outfile=./$(DATA)/web/js/form.js --minify
|
||||
-$(ESBUILD) --bundle ts/setup.ts $(SOURCEMAP) --outfile=./$(DATA)/web/js/setup.js --minify
|
||||
$(COPYTS)
|
||||
|
||||
swagger:
|
||||
go get github.com/swaggo/swag/cmd/swag
|
||||
$(GOBINARY) get github.com/swaggo/swag/cmd/swag
|
||||
swag init -g main.go
|
||||
|
||||
version:
|
||||
python3 version.py auto version.go
|
||||
|
||||
compile:
|
||||
$(info Downloading deps)
|
||||
go mod download
|
||||
$(GOBINARY) mod download
|
||||
$(info Building)
|
||||
mkdir -p build
|
||||
CGO_ENABLED=0 go build -o build/jfa-go *.go
|
||||
CGO_ENABLED=0 $(GOBINARY) build -ldflags="-s -w $(LDFLAGS)" $(TAGS) -o build/jfa-go
|
||||
|
||||
compress:
|
||||
upx --lzma build/jfa-go
|
||||
|
||||
copy:
|
||||
$(info copying css)
|
||||
-mkdir -p build/data/web/css
|
||||
cp -r css build/data/web/
|
||||
cp node_modules/a17t/dist/a17t.css build/data/web/css/
|
||||
cp -r node_modules/remixicon/fonts/remixicon.css node_modules/remixicon/fonts/remixicon.woff2 build/data/web/css/
|
||||
$(info copying html)
|
||||
cp -r html build/data/
|
||||
$(info copying static data)
|
||||
-mkdir -p build/data/web
|
||||
cp -r static/* build/data/web/
|
||||
$(info copying language files)
|
||||
cp -r lang build/data/
|
||||
bundle-css:
|
||||
-mkdir -p $(DATA)/web/css
|
||||
$(info bundling css)
|
||||
$(ESBUILD) --bundle css/base.css --outfile=$(DATA)/web/css/bundle.css --external:remixicon.css --minify
|
||||
|
||||
copy:
|
||||
$(info copying fonts)
|
||||
cp -r node_modules/remixicon/fonts/remixicon.css node_modules/remixicon/fonts/remixicon.woff2 $(DATA)/web/css/
|
||||
$(info copying html)
|
||||
cp -r html $(DATA)/
|
||||
$(info copying static data)
|
||||
-mkdir -p $(DATA)/web
|
||||
cp -r static/* $(DATA)/web/
|
||||
$(info copying systemd service)
|
||||
cp jfa-go.service $(DATA)/
|
||||
$(info copying language files)
|
||||
cp -r lang $(DATA)/
|
||||
cp LICENSE $(DATA)/
|
||||
|
||||
# internal-files:
|
||||
# python3 scripts/embed.py internal
|
||||
#
|
||||
# external-files:
|
||||
# python3 scripts/embed.py external
|
||||
# -mkdir -p build
|
||||
# $(info copying internal data into build/)
|
||||
# cp -r data build/
|
||||
|
||||
install:
|
||||
cp -r build $(DESTDIR)/jfa-go
|
||||
|
||||
all: configuration npm email version typescript swagger compile copy
|
||||
debug: configuration npm email version ts-debug swagger compile copy
|
||||
clean:
|
||||
-rm -r $(DATA)
|
||||
-rm -r build
|
||||
-rm mail/*.html
|
||||
-rm docs/docs.go docs/swagger.json docs/swagger.yaml
|
||||
go clean
|
||||
|
||||
all: configuration npm email typescript bundle-css swagger copy compile
|
||||
|
||||
63
README.md
@@ -1,8 +1,12 @@
|
||||
# 
|
||||

|
||||
[](https://drone.hrfee.dev/hrfee/jfa-go)
|
||||
[](https://hub.docker.com/r/hrfee/jfa-go)
|
||||
[](https://weblate.hrfee.pw/engage/jfa-go/)
|
||||
|
||||
jfa-go is a user management app for [Jellyfin](https://github.com/jellyfin/jellyfin) that provides invite-based account creation as well as other features that make one's instance much easier to manage.
|
||||
|
||||
I chose to rewrite the python [jellyfin-accounts](https://github.com/hrfee/jellyfin-accounts) in Go mainly as a learning experience, but also to slightly improve speeds and efficiency.
|
||||
##### Downloads:
|
||||
##### [dockerhub](https://hub.docker.com/r/hrfee/jfa-go) | [stable](https://github.com/hrfee/jfa-go/releases) | [nightly](https://builds.hrfee.pw/view/hrfee/jfa-go) | [aur stable](https://aur.archlinux.org/packages/jfa-go) | [aur binary](https://aur.archlinux.org/packages/jfa-go-bin) | [aur nightly](https://aur.archlinux.org/packages/jfa-go-git)
|
||||
---
|
||||
jfa-go is a user management app for [Jellyfin](https://github.com/jellyfin/jellyfin) (and now [Emby](https://emby.media/)) that provides invite-based account creation as well as other features that make one's instance much easier to manage.
|
||||
|
||||
#### Features
|
||||
* 🧑 Invite based account creation: Sends invites to your friends or family, and let them choose their own username and password without relying on you.
|
||||
@@ -10,48 +14,53 @@ I chose to rewrite the python [jellyfin-accounts](https://github.com/hrfee/jelly
|
||||
* Granular control over invites: Validity period as well as number of uses can be specified.
|
||||
* Account profiles: Assign settings profiles to invites so new users have your predefined permissions, homescreen layout, etc. applied to their account on creation.
|
||||
* Password validation: Ensure users choose a strong password.
|
||||
* ⌛ User expiry: Specify a validity period, and new users accounts will be disabled/deleted after it. The period can be manually extended too.
|
||||
* 🔗 Ombi Integration: Automatically creates Ombi accounts for new users using their email address and login details, and your own defined set of permissions.
|
||||
* Account management: Apply settings to your users individually or en masse, and delete users, optionally sending them an email notification with a reason.
|
||||
* Telegram Integration: Verify users via telegram, and send Password Resets, Announcements, etc. through it.
|
||||
* 📨 Email storage: Add your existing users email addresses through the UI, and jfa-go will ask new users for them on account creation.
|
||||
* Email addresses can optionally be used instead of usernames
|
||||
* 🔑 Password resets: When user's forget their passwords and request a change in Jellyfin, jfa-go reads the PIN from the created file and sends it straight to the user via email.
|
||||
* 🔑 Password resets: When users forget their passwords and request a change in Jellyfin, jfa-go reads the PIN from the created file and sends it straight to the user via email/telegram.
|
||||
* Notifications: Get notified when someone creates an account, or an invite expires.
|
||||
* 📣 Announcements: Bulk message your users with announcements about your server.
|
||||
* Authentication via Jellyfin: Instead of using separate credentials for jfa-go and Jellyfin, jfa-go can use it as the authentication provider.
|
||||
* Enables the usage of jfa-go by multiple people
|
||||
* 🌓 Customizable look
|
||||
* 🌓 Customizations
|
||||
* Customize emails with variables and markdown
|
||||
* Specify contact and help messages to appear in emails and pages
|
||||
* Light and dark themes available
|
||||
|
||||
## Interface
|
||||
#### Interface
|
||||
<p align="center">
|
||||
<img src="images/demo.gif" width="100%"></img>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img src="images/invites.png" width="48%" style="margin-left: 1.5%;" alt="Invites tab"></img>
|
||||
<img src="images/accounts.png" width="48%" style="margin-right: 1.5%;" alt="Accounts tab"></img>
|
||||
<img src="images/invites.png" width="31%" style="margin-left: 1.5%;" alt="Invites tab"></img>
|
||||
<img src="images/accounts.png" width="31%" style="margin-right: 1.5%;" alt="Accounts tab"></img>
|
||||
<img src="images/create.png" width="31%" style="margin-right: 1.5%;" alt="Accounts creation"></img>
|
||||
</p>
|
||||
|
||||
#### Install
|
||||
|
||||
Available on the AUR as [jfa-go](https://aur.archlinux.org/packages/jfa-go/) or [jfa-go-git](https://aur.archlinux.org/packages/jfa-go-git/).
|
||||
|
||||
For other platforms, grab an archive from the release section for your platform (or nightly builds [here](https://builds.hrfee.pw/view/hrfee/jfa-go)), and extract `jfa-go` and `data` to the same directory.
|
||||
* For linux users, you can place them inside `/opt/jfa-go` and then run
|
||||
`sudo ln -s /opt/jfa-go/jfa-go /usr/bin/jfa-go` to place it in your PATH.
|
||||
|
||||
Run the executable to start.
|
||||
|
||||
For [docker](https://hub.docker.com/repository/docker/hrfee/jfa-go), run:
|
||||
```
|
||||
The [Docker](https://hub.docker.com/r/hrfee/jfa-go) image is your best bet.
|
||||
```sh
|
||||
docker create \
|
||||
--name "jfa-go" \ # Whatever you want to name it
|
||||
-p 8056:8056 \
|
||||
# -p 8057:8057 if using tls
|
||||
-v /path/to/.config/jfa-go:/data \ # Path to wherever you want to store the config file and other data
|
||||
-v /path/to/jellyfin:/jf \ # Path to jellyfin config directory
|
||||
-v /path/to/jellyfin:/jf \ # Path to Jellyfin config directory, ignore if using Emby
|
||||
-v /etc/localtime:/etc/localtime:ro \ # Makes sure time is correct
|
||||
hrfee/jfa-go # hrfee/jfa-go:unstable for latest build from git
|
||||
```
|
||||
Available on the AUR as [jfa-go](https://aur.archlinux.org/packages/jfa-go/), [jfa-go-bin](https://aur.archlinux.org/packages/jfa-go) or [jfa-go-git](https://aur.archlinux.org/packages/jfa-go-git/).
|
||||
|
||||
For other platforms, grab an archive from the release section for your platform (or nightly builds [here](https://builds.hrfee.dev/view/hrfee/jfa-go)), and extract the `jfa-go` executable to somewhere useful.
|
||||
* For \*nix/macOS users, `chmod +x jfa-go` then place it somewhere in your PATH like `/usr/bin`.
|
||||
|
||||
Run the executable to start.
|
||||
|
||||
|
||||
#### Build from source
|
||||
If you're using docker, a Dockerfile is provided that builds from source.
|
||||
@@ -61,8 +70,6 @@ Otherwise, full build instructions can be found [here](https://github.com/hrfee/
|
||||
#### Usage
|
||||
Simply run `jfa-go` to start the application. A setup wizard will start on `localhost:8056` (or your own specified address). Upon completion, refresh the page.
|
||||
|
||||
Note: jfa-go does not run as a daemon by default. You'll need to figure this out yourself.
|
||||
|
||||
```
|
||||
Usage of ./jfa-go:
|
||||
-config string
|
||||
@@ -79,6 +86,11 @@ Usage of ./jfa-go:
|
||||
Enable swagger at /swagger/index.html
|
||||
```
|
||||
|
||||
#### Systemd
|
||||
jfa-go does not run as a daemon by default. Run `jfa-go systemd` to create a systemd `.service` file in your current directory, which you can copy into `~/.config/systemd/user` or somewhere else.
|
||||
|
||||
---
|
||||
|
||||
If you're switching from jellyfin-accounts, copy your existing `~/.jf-accounts` to:
|
||||
|
||||
* `XDG_CONFIG_DIR/jfa-go` (usually ~/.config/jfa-go) on \*nix systems,
|
||||
@@ -86,3 +98,10 @@ If you're switching from jellyfin-accounts, copy your existing `~/.jf-accounts`
|
||||
* `~/Library/Application Support/jfa-go` on macOS.
|
||||
|
||||
(or specify config/data path with `-config/-data` respectively.)
|
||||
|
||||
#### Contributing
|
||||
See [CONTRIBUTING.md](https://github.com/hrfee/jfa-go/blob/main/CONTRIBUTING.md).
|
||||
##### Translation
|
||||
[](https://weblate.hrfee.pw/engage/jfa-go/)
|
||||
|
||||
For translations, use the weblate instance [here](https://weblate.hrfee.pw/engage/jfa-go/). You can login with github.
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
This branch is for experimenting with [a17t](https://a17t.miles.land/) to replace bootstrap. Page structure is pretty much done (except setup.html), so i'm currently integrating this with the main app and existing web code.
|
||||
|
||||
#### todo
|
||||
**general**
|
||||
* [x] modal implementation
|
||||
* [x] animations
|
||||
* [x] utilities
|
||||
* [x] CSS for light & dark
|
||||
|
||||
**admin**
|
||||
* [x] invites tab
|
||||
* [x] accounts tab
|
||||
* [x] settings tab
|
||||
* [x] modals
|
||||
* [ ] integration with existing code
|
||||
|
||||
**invites**
|
||||
* [x] page design
|
||||
* [ ] integration with existing code
|
||||
|
||||
#### screenshots
|
||||
##### dark
|
||||
<p>
|
||||
<img src="images/dark/invites.png" alt="invites" style="width: 32%; height: auto;">
|
||||
<img src="images/dark/accounts.png" alt="accounts" style="width: 32%; height: auto;">
|
||||
<img src="images/dark/settings.png" alt="settings" style="width: 32%; height: auto;">
|
||||
<img src="images/dark/login-modal.png" alt="login modal" style="width: 32%; height: auto;">
|
||||
<img src="images/dark/modify-settings.png" alt="modify user settings modal" style="width: 32%; height: auto;">
|
||||
</p>
|
||||
|
||||
##### light
|
||||
<p>
|
||||
<img src="images/light/invites.png" alt="invites" style="width: 32%; height: auto;">
|
||||
<img src="images/light/accounts.png" alt="accounts" style="width: 32%; height: auto;">
|
||||
<img src="images/light/settings.png" alt="settings" style="width: 32%; height: auto;">
|
||||
<img src="images/light/login-modal.png" alt="login modal" style="width: 32%; height: auto;">
|
||||
<img src="images/light/modify-settings.png" alt="modify user settings modal" style="width: 32%; height: auto;">
|
||||
</p>
|
||||
154
args.go
Normal file
@@ -0,0 +1,154 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (app *appContext) loadArgs(firstCall bool) {
|
||||
if firstCall {
|
||||
flag.Usage = helpFunc
|
||||
help := flag.Bool("help", false, "prints this message.")
|
||||
flag.BoolVar(help, "h", false, "SHORTHAND")
|
||||
|
||||
DATA = flag.String("data", app.dataPath, "alternate path to data directory.")
|
||||
flag.StringVar(DATA, "d", app.dataPath, "SHORTHAND")
|
||||
CONFIG = flag.String("config", app.configPath, "alternate path to config file.")
|
||||
flag.StringVar(CONFIG, "c", app.configPath, "SHORTHAND")
|
||||
HOST = flag.String("host", "", "alternate address to host web ui on.")
|
||||
PORT = flag.Int("port", 0, "alternate port to host web ui on.")
|
||||
flag.IntVar(PORT, "p", 0, "SHORTHAND")
|
||||
DEBUG = flag.Bool("debug", false, "Enables debug logging.")
|
||||
PPROF = flag.Bool("pprof", false, "Exposes pprof profiler on /debug/pprof.")
|
||||
SWAGGER = flag.Bool("swagger", false, "Enable swagger at /swagger/index.html")
|
||||
|
||||
flag.Parse()
|
||||
if *help {
|
||||
flag.Usage()
|
||||
os.Exit(0)
|
||||
}
|
||||
if *SWAGGER {
|
||||
os.Setenv("SWAGGER", "1")
|
||||
}
|
||||
if *DEBUG {
|
||||
os.Setenv("DEBUG", "1")
|
||||
}
|
||||
if *PPROF {
|
||||
os.Setenv("PPROF", "1")
|
||||
}
|
||||
}
|
||||
|
||||
if os.Getenv("SWAGGER") == "1" {
|
||||
*SWAGGER = true
|
||||
}
|
||||
if os.Getenv("DEBUG") == "1" {
|
||||
*DEBUG = true
|
||||
}
|
||||
if os.Getenv("PPROF") == "1" {
|
||||
*PPROF = true
|
||||
}
|
||||
// attempt to apply command line flags correctly
|
||||
if app.configPath == *CONFIG && app.dataPath != *DATA {
|
||||
app.dataPath = *DATA
|
||||
app.configPath = filepath.Join(app.dataPath, "config.ini")
|
||||
} else if app.configPath != *CONFIG && app.dataPath == *DATA {
|
||||
app.configPath = *CONFIG
|
||||
} else {
|
||||
app.configPath = *CONFIG
|
||||
app.dataPath = *DATA
|
||||
}
|
||||
|
||||
// Previously used for self-restarts but leaving them here as they might be useful.
|
||||
if v := os.Getenv("JFA_CONFIGPATH"); v != "" {
|
||||
app.configPath = v
|
||||
}
|
||||
if v := os.Getenv("JFA_DATAPATH"); v != "" {
|
||||
app.dataPath = v
|
||||
}
|
||||
|
||||
os.Setenv("JFA_CONFIGPATH", app.configPath)
|
||||
os.Setenv("JFA_DATAPATH", app.dataPath)
|
||||
}
|
||||
|
||||
/* Adds start/stop/systemd to help message, and
|
||||
also gets rid of usage for shorthand flags, and merge them with the full-length one.
|
||||
implementation is 🤢, will clean this up eventually.
|
||||
-h SHORTHAND
|
||||
-help
|
||||
prints this message.
|
||||
becomes:
|
||||
-help, -h
|
||||
prints this message.
|
||||
*/
|
||||
func helpFunc() {
|
||||
fmt.Fprint(os.Stderr, `Usage of jfa-go:
|
||||
start
|
||||
start jfa-go as a daemon and run in the background.
|
||||
stop
|
||||
stop a daemonized instance of jfa-go.
|
||||
systemd
|
||||
generate a systemd .service file.
|
||||
`)
|
||||
shortHands := []string{"-help", "-data", "-config", "-port"}
|
||||
var b bytes.Buffer
|
||||
// Write defaults into buffer then remove any shorthands
|
||||
flag.CommandLine.SetOutput(&b)
|
||||
flag.PrintDefaults()
|
||||
flag.CommandLine.SetOutput(os.Stderr)
|
||||
scanner := bufio.NewScanner(&b)
|
||||
out := ""
|
||||
line := scanner.Text()
|
||||
eof := !scanner.Scan()
|
||||
lastLine := false
|
||||
for !eof || lastLine {
|
||||
nextline := scanner.Text()
|
||||
start := 0
|
||||
if len(nextline) != 0 {
|
||||
for nextline[start] == ' ' && start < len(nextline) {
|
||||
start++
|
||||
}
|
||||
}
|
||||
if strings.Contains(line, "SHORTHAND") || (len(nextline) != 0 && strings.Contains(nextline, "SHORTHAND") && nextline[start] != '-') {
|
||||
line = nextline
|
||||
if lastLine {
|
||||
break
|
||||
}
|
||||
eof := !scanner.Scan()
|
||||
if eof {
|
||||
lastLine = true
|
||||
}
|
||||
continue
|
||||
}
|
||||
// if !strings.Contains(line, "SHORTHAND") && !(strings.Contains(nextline, "SHORTHAND") && !strings.Contains(nextline, "-")) {
|
||||
match := false
|
||||
for i, c := range line {
|
||||
if c != '-' {
|
||||
continue
|
||||
}
|
||||
for _, s := range shortHands {
|
||||
if i+len(s) <= len(line) && line[i:i+len(s)] == s {
|
||||
out += line[:i+len(s)] + ", " + s[:2] + line[i+len(s):] + "\n"
|
||||
match = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if !match {
|
||||
out += line + "\n"
|
||||
}
|
||||
line = nextline
|
||||
if lastLine {
|
||||
break
|
||||
}
|
||||
eof := !scanner.Scan()
|
||||
if eof {
|
||||
lastLine = true
|
||||
}
|
||||
}
|
||||
fmt.Fprint(os.Stderr, out)
|
||||
}
|
||||
9
auth.go
@@ -135,10 +135,7 @@ func (app *appContext) getTokenLogin(gc *gin.Context) {
|
||||
return
|
||||
}
|
||||
if !match {
|
||||
var status int
|
||||
var err error
|
||||
var user map[string]interface{}
|
||||
user, status, err = app.authJf.Authenticate(creds[0], creds[1])
|
||||
user, status, err := app.authJf.Authenticate(creds[0], creds[1])
|
||||
if status != 200 || err != nil {
|
||||
if status == 401 || status == 400 {
|
||||
app.info.Println("Auth denied: Invalid username/password (Jellyfin)")
|
||||
@@ -149,9 +146,9 @@ func (app *appContext) getTokenLogin(gc *gin.Context) {
|
||||
respond(500, "Jellyfin error", gc)
|
||||
return
|
||||
}
|
||||
jfID = user["Id"].(string)
|
||||
jfID = user.ID
|
||||
if app.config.Section("ui").Key("admin_only").MustBool(true) {
|
||||
if !user["Policy"].(map[string]interface{})["IsAdministrator"].(bool) {
|
||||
if !user.Policy.IsAdministrator {
|
||||
app.debug.Printf("Auth denied: Users \"%s\" isn't admin", creds[0])
|
||||
respond(401, "Unauthorized", gc)
|
||||
return
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"log"
|
||||
)
|
||||
|
||||
// TimeoutHandler recovers from an http timeout.
|
||||
// TimeoutHandler recovers from an http timeout or panic.
|
||||
type TimeoutHandler func()
|
||||
|
||||
// NewTimeoutHandler returns a new Timeout handler.
|
||||
|
||||
170
config.go
@@ -2,6 +2,8 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -9,31 +11,22 @@ import (
|
||||
"gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
/*var DeCamel ini.NameMapper = func(raw string) string {
|
||||
out := make([]rune, 0, len(raw))
|
||||
upper := 0
|
||||
for _, c := range raw {
|
||||
if unicode.IsUpper(c) {
|
||||
upper++
|
||||
}
|
||||
if upper == 2 {
|
||||
out = append(out, '_')
|
||||
upper = 0
|
||||
}
|
||||
out = append(out, unicode.ToLower(c))
|
||||
var emailEnabled = false
|
||||
var messagesEnabled = false
|
||||
var telegramEnabled = false
|
||||
|
||||
func (app *appContext) GetPath(sect, key string) (fs.FS, string) {
|
||||
val := app.config.Section(sect).Key(key).MustString("")
|
||||
if strings.HasPrefix(val, "jfa-go:") {
|
||||
return localFS, strings.TrimPrefix(val, "jfa-go:")
|
||||
}
|
||||
return string(out)
|
||||
dir, file := filepath.Split(val)
|
||||
return os.DirFS(dir), file
|
||||
}
|
||||
|
||||
func (app *appContext) loadDefaults() (err error) {
|
||||
var cfb []byte
|
||||
cfb, err = ioutil.ReadFile(app.configBase_path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
json.Unmarshal(cfb, app.defaults)
|
||||
return
|
||||
}*/
|
||||
func (app *appContext) MustSetValue(section, key, val string) {
|
||||
app.config.Section(section).Key(key).SetValue(app.config.Section(section).Key(key).MustString(val))
|
||||
}
|
||||
|
||||
func (app *appContext) loadConfig() error {
|
||||
var err error
|
||||
@@ -42,45 +35,136 @@ func (app *appContext) loadConfig() error {
|
||||
return err
|
||||
}
|
||||
|
||||
app.config.Section("jellyfin").Key("public_server").SetValue(app.config.Section("jellyfin").Key("public_server").MustString(app.config.Section("jellyfin").Key("server").String()))
|
||||
app.MustSetValue("jellyfin", "public_server", app.config.Section("jellyfin").Key("server").String())
|
||||
|
||||
for _, key := range app.config.Section("files").Keys() {
|
||||
// if key.MustString("") == "" && key.Name() != "custom_css" {
|
||||
// key.SetValue(filepath.Join(app.data_path, (key.Name() + ".json")))
|
||||
// }
|
||||
if key.Name() != "html_templates" {
|
||||
if name := key.Name(); name != "html_templates" && name != "lang_files" {
|
||||
key.SetValue(key.MustString(filepath.Join(app.dataPath, (key.Name() + ".json"))))
|
||||
}
|
||||
}
|
||||
for _, key := range []string{"user_configuration", "user_displayprefs", "user_profiles", "ombi_template"} {
|
||||
// if app.config.Section("files").Key(key).MustString("") == "" {
|
||||
// key.SetValue(filepath.Join(app.data_path, (key.Name() + ".json")))
|
||||
// }
|
||||
for _, key := range []string{"user_configuration", "user_displayprefs", "user_profiles", "ombi_template", "invites", "emails", "user_template", "custom_emails", "users", "telegram_users"} {
|
||||
app.config.Section("files").Key(key).SetValue(app.config.Section("files").Key(key).MustString(filepath.Join(app.dataPath, (key + ".json"))))
|
||||
}
|
||||
app.URLBase = strings.TrimSuffix(app.config.Section("ui").Key("url_base").MustString(""), "/")
|
||||
app.config.Section("email").Key("no_username").SetValue(strconv.FormatBool(app.config.Section("email").Key("no_username").MustBool(false)))
|
||||
|
||||
app.config.Section("password_resets").Key("email_html").SetValue(app.config.Section("password_resets").Key("email_html").MustString(filepath.Join(app.localPath, "email.html")))
|
||||
app.config.Section("password_resets").Key("email_text").SetValue(app.config.Section("password_resets").Key("email_text").MustString(filepath.Join(app.localPath, "email.txt")))
|
||||
app.MustSetValue("password_resets", "email_html", "jfa-go:"+"email.html")
|
||||
app.MustSetValue("password_resets", "email_text", "jfa-go:"+"email.txt")
|
||||
|
||||
app.config.Section("invite_emails").Key("email_html").SetValue(app.config.Section("invite_emails").Key("email_html").MustString(filepath.Join(app.localPath, "invite-email.html")))
|
||||
app.config.Section("invite_emails").Key("email_text").SetValue(app.config.Section("invite_emails").Key("email_text").MustString(filepath.Join(app.localPath, "invite-email.txt")))
|
||||
app.MustSetValue("invite_emails", "email_html", "jfa-go:"+"invite-email.html")
|
||||
app.MustSetValue("invite_emails", "email_text", "jfa-go:"+"invite-email.txt")
|
||||
|
||||
app.config.Section("notifications").Key("expiry_html").SetValue(app.config.Section("notifications").Key("expiry_html").MustString(filepath.Join(app.localPath, "expired.html")))
|
||||
app.config.Section("notifications").Key("expiry_text").SetValue(app.config.Section("notifications").Key("expiry_text").MustString(filepath.Join(app.localPath, "expired.txt")))
|
||||
app.MustSetValue("email_confirmation", "email_html", "jfa-go:"+"confirmation.html")
|
||||
app.MustSetValue("email_confirmation", "email_text", "jfa-go:"+"confirmation.txt")
|
||||
|
||||
app.config.Section("notifications").Key("created_html").SetValue(app.config.Section("notifications").Key("created_html").MustString(filepath.Join(app.localPath, "created.html")))
|
||||
app.config.Section("notifications").Key("created_text").SetValue(app.config.Section("notifications").Key("created_text").MustString(filepath.Join(app.localPath, "created.txt")))
|
||||
app.MustSetValue("notifications", "expiry_html", "jfa-go:"+"expired.html")
|
||||
app.MustSetValue("notifications", "expiry_text", "jfa-go:"+"expired.txt")
|
||||
|
||||
app.config.Section("deletion").Key("email_html").SetValue(app.config.Section("deletion").Key("email_html").MustString(filepath.Join(app.localPath, "deleted.html")))
|
||||
app.config.Section("deletion").Key("email_text").SetValue(app.config.Section("deletion").Key("email_text").MustString(filepath.Join(app.localPath, "deleted.txt")))
|
||||
app.MustSetValue("notifications", "created_html", "jfa-go:"+"created.html")
|
||||
app.MustSetValue("notifications", "created_text", "jfa-go:"+"created.txt")
|
||||
|
||||
app.config.Section("jellyfin").Key("version").SetValue(VERSION)
|
||||
app.MustSetValue("deletion", "email_html", "jfa-go:"+"deleted.html")
|
||||
app.MustSetValue("deletion", "email_text", "jfa-go:"+"deleted.txt")
|
||||
|
||||
// Deletion template is good enough for these as well.
|
||||
app.MustSetValue("disable_enable", "disabled_html", "jfa-go:"+"deleted.html")
|
||||
app.MustSetValue("disable_enable", "disabled_text", "jfa-go:"+"deleted.txt")
|
||||
app.MustSetValue("disable_enable", "enabled_html", "jfa-go:"+"deleted.html")
|
||||
app.MustSetValue("disable_enable", "enabled_text", "jfa-go:"+"deleted.txt")
|
||||
|
||||
app.MustSetValue("welcome_email", "email_html", "jfa-go:"+"welcome.html")
|
||||
app.MustSetValue("welcome_email", "email_text", "jfa-go:"+"welcome.txt")
|
||||
|
||||
app.MustSetValue("template_email", "email_html", "jfa-go:"+"template.html")
|
||||
app.MustSetValue("template_email", "email_text", "jfa-go:"+"template.txt")
|
||||
|
||||
app.MustSetValue("user_expiry", "behaviour", "disable_user")
|
||||
app.MustSetValue("user_expiry", "email_html", "jfa-go:"+"user-expired.html")
|
||||
app.MustSetValue("user_expiry", "email_text", "jfa-go:"+"user-expired.txt")
|
||||
|
||||
app.config.Section("jellyfin").Key("version").SetValue(version)
|
||||
app.config.Section("jellyfin").Key("device").SetValue("jfa-go")
|
||||
app.config.Section("jellyfin").Key("device_id").SetValue(fmt.Sprintf("jfa-go-%s-%s", VERSION, COMMIT))
|
||||
app.config.Section("jellyfin").Key("device_id").SetValue(fmt.Sprintf("jfa-go-%s-%s", version, commit))
|
||||
messagesEnabled = app.config.Section("messages").Key("enabled").MustBool(false)
|
||||
telegramEnabled = app.config.Section("telegram").Key("enabled").MustBool(false)
|
||||
if !messagesEnabled {
|
||||
emailEnabled = false
|
||||
telegramEnabled = false
|
||||
} else if app.config.Section("email").Key("method").MustString("") == "" {
|
||||
emailEnabled = false
|
||||
} else {
|
||||
emailEnabled = true
|
||||
}
|
||||
if !emailEnabled && !telegramEnabled {
|
||||
messagesEnabled = false
|
||||
}
|
||||
|
||||
app.MustSetValue("updates", "enabled", "true")
|
||||
releaseChannel := app.config.Section("updates").Key("channel").String()
|
||||
if app.config.Section("updates").Key("enabled").MustBool(false) {
|
||||
v := version
|
||||
if releaseChannel == "stable" {
|
||||
if version == "git" {
|
||||
v = "0.0.0"
|
||||
}
|
||||
} else if releaseChannel == "unstable" {
|
||||
v = "git"
|
||||
}
|
||||
app.updater = newUpdater(baseURL, namespace, repo, v, commit, updater)
|
||||
}
|
||||
if releaseChannel == "" {
|
||||
if version == "git" {
|
||||
releaseChannel = "unstable"
|
||||
} else {
|
||||
releaseChannel = "stable"
|
||||
}
|
||||
app.MustSetValue("updates", "channel", releaseChannel)
|
||||
}
|
||||
|
||||
app.storage.customEmails_path = app.config.Section("files").Key("custom_emails").String()
|
||||
app.storage.loadCustomEmails()
|
||||
|
||||
substituteStrings = app.config.Section("jellyfin").Key("substitute_jellyfin_strings").MustString("")
|
||||
|
||||
oldFormLang := app.config.Section("ui").Key("language").MustString("")
|
||||
if oldFormLang != "" {
|
||||
app.storage.lang.chosenFormLang = oldFormLang
|
||||
}
|
||||
newFormLang := app.config.Section("ui").Key("language-form").MustString("")
|
||||
if newFormLang != "" {
|
||||
app.storage.lang.chosenFormLang = newFormLang
|
||||
}
|
||||
app.storage.lang.chosenAdminLang = app.config.Section("ui").Key("language-admin").MustString("en-us")
|
||||
app.storage.lang.chosenEmailLang = app.config.Section("email").Key("language").MustString("en-us")
|
||||
app.storage.lang.chosenPWRLang = app.config.Section("password_resets").Key("language").MustString("en-us")
|
||||
app.storage.lang.chosenTelegramLang = app.config.Section("telegram").Key("language").MustString("en-us")
|
||||
|
||||
app.email = NewEmailer(app)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (app *appContext) migrateEmailConfig() {
|
||||
tempConfig, _ := ini.Load(app.configPath)
|
||||
fmt.Println(warning("Part of your email configuration will be migrated to the new \"messages\" section.\nA backup will be made."))
|
||||
err := tempConfig.SaveTo(app.configPath + "_" + commit + ".bak")
|
||||
if err != nil {
|
||||
app.err.Fatalf("Failed to backup config: %v", err)
|
||||
return
|
||||
}
|
||||
for _, setting := range []string{"use_24h", "date_format", "message"} {
|
||||
if val := app.config.Section("email").Key(setting).Value(); val != "" {
|
||||
tempConfig.Section("email").Key(setting).SetValue("")
|
||||
tempConfig.Section("messages").Key(setting).SetValue(val)
|
||||
}
|
||||
}
|
||||
if app.config.Section("messages").Key("enabled").MustBool(false) || app.config.Section("telegram").Key("enabled").MustBool(false) {
|
||||
tempConfig.Section("messages").Key("enabled").SetValue("true")
|
||||
}
|
||||
err = tempConfig.SaveTo(app.configPath)
|
||||
if err != nil {
|
||||
app.err.Fatalf("Failed to save config: %v", err)
|
||||
return
|
||||
}
|
||||
app.loadConfig()
|
||||
}
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
### fixconfig
|
||||
|
||||
Python's `json` library retains the order of data in a JSON file, which meant settings sent to the web page would be in the right order. Go's `encoding/json` and maps do not retain order, so this script opens the json file, and for each section, adds an "order" list which tells the web page in which order to display settings.
|
||||
|
||||
Python's `json` library retains the order of data in a JSON file, which meant settings sent to the web page would be in the right order. Go's `encoding/json` and maps do not retain order, so `enumerate/enumerate_config.py` opens the json file, and for each section, adds an "order" array which tells the web page in which order to display settings.
|
||||
Specify the input and output files with `-i` and `-o` respectively.
|
||||
|
||||
### jsontostruct
|
||||
|
||||
Generates a go struct from `config-base.json`. I wrote this because i was annoyed with the `ini` library, but i've since realised mapping the ini values onto it is painful.
|
||||
|
||||
|
||||
|
||||
@@ -1,541 +0,0 @@
|
||||
package main
|
||||
|
||||
type Metadata struct{
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type Config struct{
|
||||
Order []string `json:"order"`
|
||||
Jellyfin struct{
|
||||
Order []string `json:"order"`
|
||||
Meta Metadata `json:"meta"`
|
||||
Username struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"username"`
|
||||
} `json:"username" cfg:"username"`
|
||||
Password struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"password"`
|
||||
} `json:"password" cfg:"password"`
|
||||
Server struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"server"`
|
||||
} `json:"server" cfg:"server"`
|
||||
PublicServer struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"public_server"`
|
||||
} `json:"public_server" cfg:"public_server"`
|
||||
Client struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"client"`
|
||||
} `json:"client" cfg:"client"`
|
||||
Version struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"version"`
|
||||
} `json:"version" cfg:"version"`
|
||||
Device struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"device"`
|
||||
} `json:"device" cfg:"device"`
|
||||
DeviceId struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"device_id"`
|
||||
} `json:"device_id" cfg:"device_id"`
|
||||
} `json:"jellyfin"`
|
||||
Ui struct{
|
||||
Order []string `json:"order"`
|
||||
Meta Metadata `json:"meta"`
|
||||
Theme struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Options []string `json:"options"`
|
||||
Value string `json:"value" cfg:"theme"`
|
||||
} `json:"theme" cfg:"theme"`
|
||||
Host struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"host"`
|
||||
} `json:"host" cfg:"host"`
|
||||
Port struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value int `json:"value" cfg:"port"`
|
||||
} `json:"port" cfg:"port"`
|
||||
JellyfinLogin struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value bool `json:"value" cfg:"jellyfin_login"`
|
||||
} `json:"jellyfin_login" cfg:"jellyfin_login"`
|
||||
AdminOnly struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value bool `json:"value" cfg:"admin_only"`
|
||||
} `json:"admin_only" cfg:"admin_only"`
|
||||
Username struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"username"`
|
||||
} `json:"username" cfg:"username"`
|
||||
Password struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"password"`
|
||||
} `json:"password" cfg:"password"`
|
||||
Email struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"email"`
|
||||
} `json:"email" cfg:"email"`
|
||||
Debug struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value bool `json:"value" cfg:"debug"`
|
||||
} `json:"debug" cfg:"debug"`
|
||||
ContactMessage struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"contact_message"`
|
||||
} `json:"contact_message" cfg:"contact_message"`
|
||||
HelpMessage struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"help_message"`
|
||||
} `json:"help_message" cfg:"help_message"`
|
||||
SuccessMessage struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"success_message"`
|
||||
} `json:"success_message" cfg:"success_message"`
|
||||
Bs5 struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value bool `json:"value" cfg:"bs5"`
|
||||
} `json:"bs5" cfg:"bs5"`
|
||||
} `json:"ui"`
|
||||
PasswordValidation struct{
|
||||
Order []string `json:"order"`
|
||||
Meta Metadata `json:"meta"`
|
||||
Enabled struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value bool `json:"value" cfg:"enabled"`
|
||||
} `json:"enabled" cfg:"enabled"`
|
||||
MinLength struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"min_length"`
|
||||
} `json:"min_length" cfg:"min_length"`
|
||||
Upper struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"upper"`
|
||||
} `json:"upper" cfg:"upper"`
|
||||
Lower struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"lower"`
|
||||
} `json:"lower" cfg:"lower"`
|
||||
Number struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"number"`
|
||||
} `json:"number" cfg:"number"`
|
||||
Special struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"special"`
|
||||
} `json:"special" cfg:"special"`
|
||||
} `json:"password_validation"`
|
||||
Email struct{
|
||||
Order []string `json:"order"`
|
||||
Meta Metadata `json:"meta"`
|
||||
NoUsername struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value bool `json:"value" cfg:"no_username"`
|
||||
} `json:"no_username" cfg:"no_username"`
|
||||
Use24H struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value bool `json:"value" cfg:"use_24h"`
|
||||
} `json:"use_24h" cfg:"use_24h"`
|
||||
DateFormat struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"date_format"`
|
||||
} `json:"date_format" cfg:"date_format"`
|
||||
Message struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"message"`
|
||||
} `json:"message" cfg:"message"`
|
||||
Method struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Options []string `json:"options"`
|
||||
Value string `json:"value" cfg:"method"`
|
||||
} `json:"method" cfg:"method"`
|
||||
Address struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"address"`
|
||||
} `json:"address" cfg:"address"`
|
||||
From struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"from"`
|
||||
} `json:"from" cfg:"from"`
|
||||
} `json:"email"`
|
||||
PasswordResets struct{
|
||||
Order []string `json:"order"`
|
||||
Meta Metadata `json:"meta"`
|
||||
Enabled struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value bool `json:"value" cfg:"enabled"`
|
||||
} `json:"enabled" cfg:"enabled"`
|
||||
WatchDirectory struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"watch_directory"`
|
||||
} `json:"watch_directory" cfg:"watch_directory"`
|
||||
EmailHtml struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"email_html"`
|
||||
} `json:"email_html" cfg:"email_html"`
|
||||
EmailText struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"email_text"`
|
||||
} `json:"email_text" cfg:"email_text"`
|
||||
Subject struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"subject"`
|
||||
} `json:"subject" cfg:"subject"`
|
||||
} `json:"password_resets"`
|
||||
InviteEmails struct{
|
||||
Order []string `json:"order"`
|
||||
Meta Metadata `json:"meta"`
|
||||
Enabled struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value bool `json:"value" cfg:"enabled"`
|
||||
} `json:"enabled" cfg:"enabled"`
|
||||
EmailHtml struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"email_html"`
|
||||
} `json:"email_html" cfg:"email_html"`
|
||||
EmailText struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"email_text"`
|
||||
} `json:"email_text" cfg:"email_text"`
|
||||
Subject struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"subject"`
|
||||
} `json:"subject" cfg:"subject"`
|
||||
UrlBase struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"url_base"`
|
||||
} `json:"url_base" cfg:"url_base"`
|
||||
} `json:"invite_emails"`
|
||||
Notifications struct{
|
||||
Order []string `json:"order"`
|
||||
Meta Metadata `json:"meta"`
|
||||
Enabled struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value bool `json:"value" cfg:"enabled"`
|
||||
} `json:"enabled" cfg:"enabled"`
|
||||
ExpiryHtml struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"expiry_html"`
|
||||
} `json:"expiry_html" cfg:"expiry_html"`
|
||||
ExpiryText struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"expiry_text"`
|
||||
} `json:"expiry_text" cfg:"expiry_text"`
|
||||
CreatedHtml struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"created_html"`
|
||||
} `json:"created_html" cfg:"created_html"`
|
||||
CreatedText struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"created_text"`
|
||||
} `json:"created_text" cfg:"created_text"`
|
||||
} `json:"notifications"`
|
||||
Mailgun struct{
|
||||
Order []string `json:"order"`
|
||||
Meta Metadata `json:"meta"`
|
||||
ApiUrl struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"api_url"`
|
||||
} `json:"api_url" cfg:"api_url"`
|
||||
ApiKey struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"api_key"`
|
||||
} `json:"api_key" cfg:"api_key"`
|
||||
} `json:"mailgun"`
|
||||
Smtp struct{
|
||||
Order []string `json:"order"`
|
||||
Meta Metadata `json:"meta"`
|
||||
Encryption struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Options []string `json:"options"`
|
||||
Value string `json:"value" cfg:"encryption"`
|
||||
} `json:"encryption" cfg:"encryption"`
|
||||
Server struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"server"`
|
||||
} `json:"server" cfg:"server"`
|
||||
Port struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value int `json:"value" cfg:"port"`
|
||||
} `json:"port" cfg:"port"`
|
||||
Password struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"password"`
|
||||
} `json:"password" cfg:"password"`
|
||||
} `json:"smtp"`
|
||||
Files struct{
|
||||
Order []string `json:"order"`
|
||||
Meta Metadata `json:"meta"`
|
||||
Invites struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"invites"`
|
||||
} `json:"invites" cfg:"invites"`
|
||||
Emails struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"emails"`
|
||||
} `json:"emails" cfg:"emails"`
|
||||
UserTemplate struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"user_template"`
|
||||
} `json:"user_template" cfg:"user_template"`
|
||||
UserConfiguration struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"user_configuration"`
|
||||
} `json:"user_configuration" cfg:"user_configuration"`
|
||||
UserDisplayprefs struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"user_displayprefs"`
|
||||
} `json:"user_displayprefs" cfg:"user_displayprefs"`
|
||||
CustomCss struct{
|
||||
Name string `json:"name"`
|
||||
Required bool `json:"required"`
|
||||
Restart bool `json:"requires_restart"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" cfg:"custom_css"`
|
||||
} `json:"custom_css" cfg:"custom_css"`
|
||||
} `json:"files"`
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
import json
|
||||
|
||||
with open("config-formatted.json", "r") as f:
|
||||
config = json.load(f)
|
||||
|
||||
indent = 0
|
||||
|
||||
|
||||
def writeln(ln):
|
||||
global indent
|
||||
if "}" in ln and "{" not in ln:
|
||||
indent -= 1
|
||||
s.write(("\t" * indent) + ln + "\n")
|
||||
if "{" in ln and "}" not in ln:
|
||||
indent += 1
|
||||
|
||||
|
||||
with open("configStruct.go", "w") as s:
|
||||
writeln("package main")
|
||||
writeln("")
|
||||
writeln("type Metadata struct{")
|
||||
writeln('Name string `json:"name"`')
|
||||
writeln('Description string `json:"description"`')
|
||||
writeln("}")
|
||||
writeln("")
|
||||
writeln("type Config struct{")
|
||||
if "order" in config:
|
||||
writeln('Order []string `json:"order"`')
|
||||
for section in [x for x in config.keys() if x != "order"]:
|
||||
title = "".join([x.title() for x in section.split("_")])
|
||||
writeln(title + " struct{")
|
||||
if "order" in config[section]:
|
||||
writeln('Order []string `json:"order"`')
|
||||
if "meta" in config[section]:
|
||||
writeln('Meta Metadata `json:"meta"`')
|
||||
for setting in [
|
||||
x for x in config[section].keys() if x != "order" and x != "meta"
|
||||
]:
|
||||
name = "".join([x.title() for x in setting.split("_")])
|
||||
writeln(name + " struct{")
|
||||
writeln('Name string `json:"name"`')
|
||||
writeln('Required bool `json:"required"`')
|
||||
writeln('Restart bool `json:"requires_restart"`')
|
||||
writeln('Description string `json:"description"`')
|
||||
writeln('Type string `json:"type"`')
|
||||
dt = config[section][setting]["type"]
|
||||
if dt == "select":
|
||||
dt = "string"
|
||||
writeln('Options []string `json:"options"`')
|
||||
elif dt == "number":
|
||||
dt = "int"
|
||||
elif dt != "bool":
|
||||
dt = "string"
|
||||
writeln(f'Value {dt} `json:"value" cfg:"{setting}"`')
|
||||
writeln("} " + f'`json:"{setting}" cfg:"{setting}"`')
|
||||
writeln("} " + f'`json:"{section}"`')
|
||||
writeln("}")
|
||||
125
css/base.css
@@ -1,9 +1,9 @@
|
||||
@import "a17t.css";
|
||||
@import "../node_modules/a17t/dist/a17t.css";
|
||||
@import "remixicon.css";
|
||||
@import "modal.css";
|
||||
@import "dark.css";
|
||||
@import "tooltip.css";
|
||||
@import "loader.css";
|
||||
@import "./modal.css";
|
||||
@import "./dark.css";
|
||||
@import "./tooltip.css";
|
||||
@import "./loader.css";
|
||||
|
||||
:root {
|
||||
--border-width-default: 2px;
|
||||
@@ -39,6 +39,32 @@
|
||||
}
|
||||
}
|
||||
|
||||
.chip.btn:hover:not([disabled]):not(.textarea),
|
||||
.chip.btn:focus:not([disabled]):not(.textarea) {
|
||||
filter: brightness(var(--button-filter-brightness,95%));
|
||||
}
|
||||
|
||||
.banner {
|
||||
margin: calc(-1 * var(--spacing-4,1rem));
|
||||
}
|
||||
|
||||
.banner.header {
|
||||
margin-bottom: var(--spacing-4,1rem);
|
||||
}
|
||||
|
||||
.banner.footer {
|
||||
margin-top: var(--spacing-4,1rem);
|
||||
padding: var(--spacing-4,1rem);
|
||||
}
|
||||
|
||||
.modal-content .banner {
|
||||
margin-left: calc(-1 * var(--spacing-4,1rem) - 0.5%); /* Not sure why this is necessary */
|
||||
margin-right: calc(-1 * var(--spacing-4,1rem) - 0.5%);
|
||||
}
|
||||
|
||||
div.card:contains(section.banner.footer) {
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
|
||||
.tab-button {
|
||||
font-size: 2rem;
|
||||
@@ -72,10 +98,18 @@
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.mr-half {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.mr-1 {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
.p-1 {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.pb-1 {
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
@@ -92,6 +126,10 @@
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.ac {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.inline-block {
|
||||
display: inline-block;
|
||||
}
|
||||
@@ -133,6 +171,21 @@
|
||||
margin: 0.5rem;
|
||||
}
|
||||
|
||||
p.sm,
|
||||
span.sm {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
|
||||
.col.sm {
|
||||
margin: .25rem;
|
||||
}
|
||||
|
||||
.flex-col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 400px) {
|
||||
.row {
|
||||
flex-direction: column;
|
||||
@@ -148,6 +201,7 @@
|
||||
|
||||
.monospace {
|
||||
background-color: inherit; /* so we can use a17t code blocks */
|
||||
font-family: Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;
|
||||
}
|
||||
|
||||
sup.\~critical, .text-critical {
|
||||
@@ -200,7 +254,7 @@ sup.\~critical, .text-critical {
|
||||
max-width: 40%;
|
||||
min-width: 10rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
justify-content: start;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@@ -252,10 +306,18 @@ sup.\~critical, .text-critical {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.flex-auto {
|
||||
flex: auto;
|
||||
}
|
||||
|
||||
.center {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.middle {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.no-lp {
|
||||
padding-left: 0px;
|
||||
}
|
||||
@@ -370,3 +432,54 @@ p.top {
|
||||
bottom: 1rem;
|
||||
z-index: 16;
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
padding-bottom: 0.5rem;
|
||||
margin-bottom: -0.5rem;
|
||||
}
|
||||
|
||||
pre {
|
||||
white-space: pre-wrap; /* css-3 */
|
||||
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
|
||||
white-space: -pre-wrap; /* Opera 4-6 */
|
||||
white-space: -o-pre-wrap; /* Opera 7 */
|
||||
word-wrap: break-word; /* Internet Explorer 5.5+ */
|
||||
}
|
||||
|
||||
.circle {
|
||||
height: 0.5rem;
|
||||
width: 0.5rem;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.circle.\~urge {
|
||||
background-color: var(--color-urge-200);
|
||||
}
|
||||
|
||||
.markdown-box {
|
||||
max-height: 20rem;
|
||||
display: block;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
a:link:not(.lang-link):not(.\~urge) {
|
||||
color: var(--color-urge-200);
|
||||
}
|
||||
|
||||
a:visited:not(.lang-link):not(.\~urge) {
|
||||
color: var(--color-urge-100);
|
||||
}
|
||||
|
||||
a:hover:not(.lang-link):not(.\~urge), a:active:not(.lang-link):not(.\~urge) {
|
||||
color: var(--color-urge-200);
|
||||
}
|
||||
|
||||
.link-center {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.search {
|
||||
max-width: 15rem;
|
||||
min-width: 10rem;
|
||||
}
|
||||
|
||||
@@ -85,3 +85,7 @@
|
||||
.dark-only {
|
||||
display: initial;
|
||||
}
|
||||
|
||||
.dark-theme select option {
|
||||
background: #202020;
|
||||
}
|
||||
|
||||
10
daemon.go
@@ -4,7 +4,7 @@ import "time"
|
||||
|
||||
// https://bbengfort.github.io/snippets/2016/06/26/background-work-goroutines-timer.html THANKS
|
||||
|
||||
type repeater struct {
|
||||
type inviteDaemon struct {
|
||||
Stopped bool
|
||||
ShutdownChannel chan string
|
||||
Interval time.Duration
|
||||
@@ -12,8 +12,8 @@ type repeater struct {
|
||||
app *appContext
|
||||
}
|
||||
|
||||
func newRepeater(interval time.Duration, app *appContext) *repeater {
|
||||
return &repeater{
|
||||
func newInviteDaemon(interval time.Duration, app *appContext) *inviteDaemon {
|
||||
return &inviteDaemon{
|
||||
Stopped: false,
|
||||
ShutdownChannel: make(chan string),
|
||||
Interval: interval,
|
||||
@@ -22,7 +22,7 @@ func newRepeater(interval time.Duration, app *appContext) *repeater {
|
||||
}
|
||||
}
|
||||
|
||||
func (rt *repeater) run() {
|
||||
func (rt *inviteDaemon) run() {
|
||||
rt.app.info.Println("Invite daemon started")
|
||||
for {
|
||||
select {
|
||||
@@ -42,7 +42,7 @@ func (rt *repeater) run() {
|
||||
}
|
||||
}
|
||||
|
||||
func (rt *repeater) shutdown() {
|
||||
func (rt *inviteDaemon) shutdown() {
|
||||
rt.Stopped = true
|
||||
rt.ShutdownChannel <- "Down"
|
||||
<-rt.ShutdownChannel
|
||||
|
||||
848
email.go
@@ -4,20 +4,37 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net/smtp"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
textTemplate "text/template"
|
||||
"time"
|
||||
|
||||
"github.com/gomarkdown/markdown"
|
||||
"github.com/gomarkdown/markdown/html"
|
||||
"github.com/itchyny/timefmt-go"
|
||||
jEmail "github.com/jordan-wright/email"
|
||||
"github.com/knz/strtime"
|
||||
"github.com/mailgun/mailgun-go/v4"
|
||||
)
|
||||
|
||||
// implements email sending, right now via smtp or mailgun.
|
||||
type emailClient interface {
|
||||
send(address, fromName, fromAddr string, email *Email) error
|
||||
type EmailClient interface {
|
||||
Send(fromName, fromAddr string, message *Message, address ...string) error
|
||||
}
|
||||
|
||||
type DummyClient struct{}
|
||||
|
||||
func (dc *DummyClient) Send(fromName, fromAddr string, email *Message, address ...string) error {
|
||||
fmt.Printf("FROM: %s <%s>\nTO: %s\nTEXT: %s\n", fromName, fromAddr, strings.Join(address, ", "), email.Text)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Mailgun client implements emailClient.
|
||||
@@ -25,14 +42,17 @@ type Mailgun struct {
|
||||
client *mailgun.MailgunImpl
|
||||
}
|
||||
|
||||
func (mg *Mailgun) send(address, fromName, fromAddr string, email *Email) error {
|
||||
func (mg *Mailgun) Send(fromName, fromAddr string, email *Message, address ...string) error {
|
||||
message := mg.client.NewMessage(
|
||||
fmt.Sprintf("%s <%s>", fromName, fromAddr),
|
||||
email.subject,
|
||||
email.text,
|
||||
address,
|
||||
email.Subject,
|
||||
email.Text,
|
||||
)
|
||||
message.SetHtml(email.html)
|
||||
for _, a := range address {
|
||||
// Adding variable tells mailgun to do a batch send, so users don't see other recipients.
|
||||
message.AddRecipientAndVariables(a, map[string]interface{}{"unique_id": a})
|
||||
}
|
||||
message.SetHtml(email.HTML)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
|
||||
defer cancel()
|
||||
_, _, err := mg.client.Send(ctx, message)
|
||||
@@ -41,63 +61,70 @@ func (mg *Mailgun) send(address, fromName, fromAddr string, email *Email) error
|
||||
|
||||
// SMTP supports SSL/TLS and STARTTLS; implements emailClient.
|
||||
type SMTP struct {
|
||||
sslTLS bool
|
||||
server string
|
||||
port int
|
||||
auth smtp.Auth
|
||||
sslTLS bool
|
||||
server string
|
||||
port int
|
||||
auth smtp.Auth
|
||||
tlsConfig *tls.Config
|
||||
}
|
||||
|
||||
func (sm *SMTP) send(address, fromName, fromAddr string, email *Email) error {
|
||||
e := jEmail.NewEmail()
|
||||
e.Subject = email.subject
|
||||
e.From = fmt.Sprintf("%s <%s>", fromName, fromAddr)
|
||||
e.To = []string{address}
|
||||
e.Text = []byte(email.text)
|
||||
e.HTML = []byte(email.html)
|
||||
func (sm *SMTP) Send(fromName, fromAddr string, email *Message, address ...string) error {
|
||||
server := fmt.Sprintf("%s:%d", sm.server, sm.port)
|
||||
tlsConfig := &tls.Config{
|
||||
InsecureSkipVerify: false,
|
||||
ServerName: sm.server,
|
||||
}
|
||||
from := fmt.Sprintf("%s <%s>", fromName, fromAddr)
|
||||
var wg sync.WaitGroup
|
||||
var err error
|
||||
fmt.Println(server)
|
||||
// err = e.Send(server, sm.auth)
|
||||
if sm.sslTLS {
|
||||
err = e.SendWithTLS(server, sm.auth, tlsConfig)
|
||||
} else {
|
||||
err = e.SendWithStartTLS(server, sm.auth, tlsConfig)
|
||||
for _, addr := range address {
|
||||
wg.Add(1)
|
||||
go func(addr string) {
|
||||
defer wg.Done()
|
||||
e := jEmail.NewEmail()
|
||||
e.Subject = email.Subject
|
||||
e.From = from
|
||||
e.Text = []byte(email.Text)
|
||||
e.HTML = []byte(email.HTML)
|
||||
e.To = []string{addr}
|
||||
if sm.sslTLS {
|
||||
err = e.SendWithTLS(server, sm.auth, sm.tlsConfig)
|
||||
} else {
|
||||
err = e.SendWithStartTLS(server, sm.auth, sm.tlsConfig)
|
||||
}
|
||||
}(addr)
|
||||
}
|
||||
wg.Wait()
|
||||
return err
|
||||
}
|
||||
|
||||
// Emailer contains the email sender, email content, and methods to construct message content.
|
||||
// Emailer contains the email sender, translations, and methods to construct messages.
|
||||
type Emailer struct {
|
||||
fromAddr, fromName string
|
||||
sender emailClient
|
||||
lang emailLang
|
||||
sender EmailClient
|
||||
}
|
||||
|
||||
// Email stores content.
|
||||
type Email struct {
|
||||
subject string
|
||||
html, text string
|
||||
// Message stores content.
|
||||
type Message struct {
|
||||
Subject string `json:"subject"`
|
||||
HTML string `json:"html"`
|
||||
Text string `json:"text"`
|
||||
Markdown string `json:"markdown"`
|
||||
}
|
||||
|
||||
func (emailer *Emailer) formatExpiry(expiry time.Time, tzaware bool, datePattern, timePattern string) (d, t, expiresIn string) {
|
||||
d, _ = strtime.Strftime(expiry, datePattern)
|
||||
t, _ = strtime.Strftime(expiry, timePattern)
|
||||
d = timefmt.Format(expiry, datePattern)
|
||||
t = timefmt.Format(expiry, timePattern)
|
||||
currentTime := time.Now()
|
||||
if tzaware {
|
||||
currentTime = currentTime.UTC()
|
||||
}
|
||||
_, _, days, hours, minutes, _ := timeDiff(expiry, currentTime)
|
||||
if days != 0 {
|
||||
expiresIn += fmt.Sprintf("%dd ", days)
|
||||
expiresIn += strconv.Itoa(days) + "d "
|
||||
}
|
||||
if hours != 0 {
|
||||
expiresIn += fmt.Sprintf("%dh ", hours)
|
||||
expiresIn += strconv.Itoa(hours) + "h "
|
||||
}
|
||||
if minutes != 0 {
|
||||
expiresIn += fmt.Sprintf("%dm ", minutes)
|
||||
expiresIn += strconv.Itoa(minutes) + "m "
|
||||
}
|
||||
expiresIn = strings.TrimSuffix(expiresIn, " ")
|
||||
return
|
||||
@@ -108,6 +135,7 @@ func NewEmailer(app *appContext) *Emailer {
|
||||
emailer := &Emailer{
|
||||
fromAddr: app.config.Section("email").Key("address").String(),
|
||||
fromName: app.config.Section("email").Key("from").String(),
|
||||
lang: app.storage.lang.Email[app.storage.lang.chosenEmailLang],
|
||||
}
|
||||
method := app.config.Section("email").Key("method").String()
|
||||
if method == "smtp" {
|
||||
@@ -121,9 +149,14 @@ func NewEmailer(app *appContext) *Emailer {
|
||||
} else {
|
||||
username = emailer.fromAddr
|
||||
}
|
||||
emailer.NewSMTP(app.config.Section("smtp").Key("server").String(), app.config.Section("smtp").Key("port").MustInt(465), username, app.config.Section("smtp").Key("password").String(), sslTls)
|
||||
err := emailer.NewSMTP(app.config.Section("smtp").Key("server").String(), app.config.Section("smtp").Key("port").MustInt(465), username, app.config.Section("smtp").Key("password").String(), sslTls, app.config.Section("smtp").Key("ssl_cert").MustString(""))
|
||||
if err != nil {
|
||||
app.err.Printf("Error while initiating SMTP mailer: %v", err)
|
||||
}
|
||||
} else if method == "mailgun" {
|
||||
emailer.NewMailgun(app.config.Section("mailgun").Key("api_url").String(), app.config.Section("mailgun").Key("api_key").String())
|
||||
} else if method == "dummy" {
|
||||
emailer.sender = &DummyClient{}
|
||||
}
|
||||
return emailer
|
||||
}
|
||||
@@ -133,7 +166,7 @@ func (emailer *Emailer) NewMailgun(url, key string) {
|
||||
sender := &Mailgun{
|
||||
client: mailgun.NewMailgun(strings.Split(emailer.fromAddr, "@")[1], key),
|
||||
}
|
||||
// Mailgun client takes the base url, so we need to trim off the end (e.g 'v3/messages'
|
||||
// Mailgun client takes the base url, so we need to trim off the end (e.g 'v3/messages')
|
||||
if strings.Contains(url, "messages") {
|
||||
url = url[0:strings.LastIndex(url, "/")]
|
||||
url = url[0:strings.LastIndex(url, "/")]
|
||||
@@ -143,175 +176,640 @@ func (emailer *Emailer) NewMailgun(url, key string) {
|
||||
}
|
||||
|
||||
// NewSMTP returns an SMTP emailClient.
|
||||
func (emailer *Emailer) NewSMTP(server string, port int, username, password string, sslTLS bool) {
|
||||
func (emailer *Emailer) NewSMTP(server string, port int, username, password string, sslTLS bool, certPath string) (err error) {
|
||||
rootCAs, err := x509.SystemCertPool()
|
||||
if rootCAs == nil || err != nil {
|
||||
rootCAs = x509.NewCertPool()
|
||||
}
|
||||
if certPath != "" {
|
||||
var cert []byte
|
||||
cert, err = os.ReadFile(certPath)
|
||||
if rootCAs.AppendCertsFromPEM(cert) == false {
|
||||
err = errors.New("Failed to append cert to pool")
|
||||
}
|
||||
}
|
||||
emailer.sender = &SMTP{
|
||||
auth: smtp.PlainAuth("", username, password, server),
|
||||
server: server,
|
||||
port: port,
|
||||
sslTLS: sslTLS,
|
||||
tlsConfig: &tls.Config{
|
||||
InsecureSkipVerify: false,
|
||||
ServerName: server,
|
||||
RootCAs: rootCAs,
|
||||
},
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (emailer *Emailer) constructInvite(code string, invite Invite, app *appContext) (*Email, error) {
|
||||
email := &Email{
|
||||
subject: app.config.Section("invite_emails").Key("subject").String(),
|
||||
type templ interface {
|
||||
Execute(wr io.Writer, data interface{}) error
|
||||
}
|
||||
|
||||
func (emailer *Emailer) construct(app *appContext, section, keyFragment string, data map[string]interface{}) (html, text, markdown string, err error) {
|
||||
var tpl templ
|
||||
if substituteStrings == "" {
|
||||
data["jellyfin"] = "Jellyfin"
|
||||
} else {
|
||||
data["jellyfin"] = substituteStrings
|
||||
}
|
||||
var keys []string
|
||||
plaintext := app.config.Section("email").Key("plaintext").MustBool(false)
|
||||
telegram := app.config.Section("telegram").Key("enabled").MustBool(false)
|
||||
if plaintext {
|
||||
if telegram {
|
||||
keys = []string{"text"}
|
||||
text, markdown = "", ""
|
||||
} else {
|
||||
keys = []string{"text"}
|
||||
text = ""
|
||||
}
|
||||
} else {
|
||||
if telegram {
|
||||
keys = []string{"html", "text", "markdown"}
|
||||
} else {
|
||||
keys = []string{"html", "text"}
|
||||
}
|
||||
}
|
||||
for _, key := range keys {
|
||||
var filesystem fs.FS
|
||||
var fpath string
|
||||
if key == "markdown" {
|
||||
filesystem, fpath = app.GetPath(section, keyFragment+"text")
|
||||
} else {
|
||||
filesystem, fpath = app.GetPath(section, keyFragment+key)
|
||||
}
|
||||
if key == "html" {
|
||||
tpl, err = template.ParseFS(filesystem, fpath)
|
||||
} else {
|
||||
tpl, err = textTemplate.ParseFS(filesystem, fpath)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// For constructTemplate, if "md" is found in data it's used in stead of "text".
|
||||
foundMarkdown := false
|
||||
if key == "markdown" {
|
||||
_, foundMarkdown = data["md"]
|
||||
if foundMarkdown {
|
||||
data["plaintext"], data["md"] = data["md"], data["plaintext"]
|
||||
}
|
||||
}
|
||||
var tplData bytes.Buffer
|
||||
err = tpl.Execute(&tplData, data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if foundMarkdown {
|
||||
data["plaintext"], data["md"] = data["md"], data["plaintext"]
|
||||
}
|
||||
if key == "html" {
|
||||
html = tplData.String()
|
||||
} else if key == "text" {
|
||||
text = tplData.String()
|
||||
} else {
|
||||
markdown = tplData.String()
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (emailer *Emailer) confirmationValues(code, username, key string, app *appContext, noSub bool) map[string]interface{} {
|
||||
template := map[string]interface{}{
|
||||
"clickBelow": emailer.lang.EmailConfirmation.get("clickBelow"),
|
||||
"ifItWasNotYou": emailer.lang.Strings.get("ifItWasNotYou"),
|
||||
"confirmEmail": emailer.lang.EmailConfirmation.get("confirmEmail"),
|
||||
"message": "",
|
||||
"username": username,
|
||||
}
|
||||
if noSub {
|
||||
template["helloUser"] = emailer.lang.Strings.get("helloUser")
|
||||
empty := []string{"confirmationURL"}
|
||||
for _, v := range empty {
|
||||
template[v] = "{" + v + "}"
|
||||
}
|
||||
} else {
|
||||
message := app.config.Section("messages").Key("message").String()
|
||||
inviteLink := app.config.Section("invite_emails").Key("url_base").String()
|
||||
inviteLink = fmt.Sprintf("%s/%s?key=%s", inviteLink, code, key)
|
||||
template["helloUser"] = emailer.lang.Strings.template("helloUser", tmpl{"username": username})
|
||||
template["confirmationURL"] = inviteLink
|
||||
template["message"] = message
|
||||
}
|
||||
return template
|
||||
}
|
||||
|
||||
func (emailer *Emailer) constructConfirmation(code, username, key string, app *appContext, noSub bool) (*Message, error) {
|
||||
email := &Message{
|
||||
Subject: app.config.Section("email_confirmation").Key("subject").MustString(emailer.lang.EmailConfirmation.get("title")),
|
||||
}
|
||||
var err error
|
||||
template := emailer.confirmationValues(code, username, key, app, noSub)
|
||||
if app.storage.customEmails.EmailConfirmation.Enabled {
|
||||
content := templateEmail(
|
||||
app.storage.customEmails.EmailConfirmation.Content,
|
||||
app.storage.customEmails.EmailConfirmation.Variables,
|
||||
nil,
|
||||
template,
|
||||
)
|
||||
email, err = emailer.constructTemplate(email.Subject, content, app)
|
||||
} else {
|
||||
email.HTML, email.Text, email.Markdown, err = emailer.construct(app, "email_confirmation", "email_", template)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return email, nil
|
||||
}
|
||||
|
||||
func (emailer *Emailer) constructTemplate(subject, md string, app *appContext) (*Message, error) {
|
||||
email := &Message{Subject: subject}
|
||||
renderer := html.NewRenderer(html.RendererOptions{Flags: html.Smartypants})
|
||||
html := markdown.ToHTML([]byte(md), nil, renderer)
|
||||
text := stripMarkdown(md)
|
||||
message := app.config.Section("messages").Key("message").String()
|
||||
var err error
|
||||
email.HTML, email.Text, email.Markdown, err = emailer.construct(app, "template_email", "email_", map[string]interface{}{
|
||||
"text": template.HTML(html),
|
||||
"plaintext": text,
|
||||
"message": message,
|
||||
"md": md,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return email, nil
|
||||
}
|
||||
|
||||
func (emailer *Emailer) inviteValues(code string, invite Invite, app *appContext, noSub bool) map[string]interface{} {
|
||||
expiry := invite.ValidTill
|
||||
d, t, expiresIn := emailer.formatExpiry(expiry, false, app.datePattern, app.timePattern)
|
||||
message := app.config.Section("email").Key("message").String()
|
||||
message := app.config.Section("messages").Key("message").String()
|
||||
inviteLink := app.config.Section("invite_emails").Key("url_base").String()
|
||||
inviteLink = fmt.Sprintf("%s/%s", inviteLink, code)
|
||||
|
||||
for _, key := range []string{"html", "text"} {
|
||||
fpath := app.config.Section("invite_emails").Key("email_" + key).String()
|
||||
tpl, err := template.ParseFiles(fpath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var tplData bytes.Buffer
|
||||
err = tpl.Execute(&tplData, map[string]string{
|
||||
"expiry_date": d,
|
||||
"expiry_time": t,
|
||||
"expires_in": expiresIn,
|
||||
"invite_link": inviteLink,
|
||||
"message": message,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if key == "html" {
|
||||
email.html = tplData.String()
|
||||
} else {
|
||||
email.text = tplData.String()
|
||||
}
|
||||
template := map[string]interface{}{
|
||||
"hello": emailer.lang.InviteEmail.get("hello"),
|
||||
"youHaveBeenInvited": emailer.lang.InviteEmail.get("youHaveBeenInvited"),
|
||||
"toJoin": emailer.lang.InviteEmail.get("toJoin"),
|
||||
"linkButton": emailer.lang.InviteEmail.get("linkButton"),
|
||||
"message": "",
|
||||
"date": d,
|
||||
"time": t,
|
||||
"expiresInMinutes": expiresIn,
|
||||
}
|
||||
return email, nil
|
||||
}
|
||||
|
||||
func (emailer *Emailer) constructExpiry(code string, invite Invite, app *appContext) (*Email, error) {
|
||||
email := &Email{
|
||||
subject: "Notice: Invite expired",
|
||||
}
|
||||
expiry := app.formatDatetime(invite.ValidTill)
|
||||
for _, key := range []string{"html", "text"} {
|
||||
fpath := app.config.Section("notifications").Key("expiry_" + key).String()
|
||||
tpl, err := template.ParseFiles(fpath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if noSub {
|
||||
template["inviteExpiry"] = emailer.lang.InviteEmail.get("inviteExpiry")
|
||||
empty := []string{"inviteURL"}
|
||||
for _, v := range empty {
|
||||
template[v] = "{" + v + "}"
|
||||
}
|
||||
var tplData bytes.Buffer
|
||||
err = tpl.Execute(&tplData, map[string]string{
|
||||
"code": code,
|
||||
"expiry": expiry,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if key == "html" {
|
||||
email.html = tplData.String()
|
||||
} else {
|
||||
email.text = tplData.String()
|
||||
}
|
||||
}
|
||||
return email, nil
|
||||
}
|
||||
|
||||
func (emailer *Emailer) constructCreated(code, username, address string, invite Invite, app *appContext) (*Email, error) {
|
||||
email := &Email{
|
||||
subject: "Notice: User created",
|
||||
}
|
||||
created := app.formatDatetime(invite.Created)
|
||||
var tplAddress string
|
||||
if app.config.Section("email").Key("no_username").MustBool(false) {
|
||||
tplAddress = "n/a"
|
||||
} else {
|
||||
tplAddress = address
|
||||
template["inviteExpiry"] = emailer.lang.InviteEmail.template("inviteExpiry", tmpl{"date": d, "time": t, "expiresInMinutes": expiresIn})
|
||||
template["inviteURL"] = inviteLink
|
||||
template["message"] = message
|
||||
}
|
||||
for _, key := range []string{"html", "text"} {
|
||||
fpath := app.config.Section("notifications").Key("created_" + key).String()
|
||||
tpl, err := template.ParseFiles(fpath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var tplData bytes.Buffer
|
||||
err = tpl.Execute(&tplData, map[string]string{
|
||||
"code": code,
|
||||
"username": username,
|
||||
"address": tplAddress,
|
||||
"time": created,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if key == "html" {
|
||||
email.html = tplData.String()
|
||||
} else {
|
||||
email.text = tplData.String()
|
||||
}
|
||||
return template
|
||||
}
|
||||
|
||||
func (emailer *Emailer) constructInvite(code string, invite Invite, app *appContext, noSub bool) (*Message, error) {
|
||||
email := &Message{
|
||||
Subject: app.config.Section("invite_emails").Key("subject").MustString(emailer.lang.InviteEmail.get("title")),
|
||||
}
|
||||
template := emailer.inviteValues(code, invite, app, noSub)
|
||||
var err error
|
||||
if app.storage.customEmails.InviteEmail.Enabled {
|
||||
content := templateEmail(
|
||||
app.storage.customEmails.InviteEmail.Content,
|
||||
app.storage.customEmails.InviteEmail.Variables,
|
||||
nil,
|
||||
template,
|
||||
)
|
||||
email, err = emailer.constructTemplate(email.Subject, content, app)
|
||||
} else {
|
||||
email.HTML, email.Text, email.Markdown, err = emailer.construct(app, "invite_emails", "email_", template)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return email, nil
|
||||
}
|
||||
|
||||
func (emailer *Emailer) constructReset(pwr PasswordReset, app *appContext) (*Email, error) {
|
||||
email := &Email{
|
||||
subject: app.config.Section("password_resets").Key("subject").MustString("Password reset - Jellyfin"),
|
||||
func (emailer *Emailer) expiryValues(code string, invite Invite, app *appContext, noSub bool) map[string]interface{} {
|
||||
expiry := app.formatDatetime(invite.ValidTill)
|
||||
template := map[string]interface{}{
|
||||
"inviteExpired": emailer.lang.InviteExpiry.get("inviteExpired"),
|
||||
"notificationNotice": emailer.lang.InviteExpiry.get("notificationNotice"),
|
||||
"code": "\"" + code + "\"",
|
||||
"time": expiry,
|
||||
}
|
||||
if noSub {
|
||||
template["expiredAt"] = emailer.lang.InviteExpiry.get("expiredAt")
|
||||
} else {
|
||||
template["expiredAt"] = emailer.lang.InviteExpiry.template("expiredAt", tmpl{"code": template["code"].(string), "time": template["time"].(string)})
|
||||
}
|
||||
return template
|
||||
}
|
||||
|
||||
func (emailer *Emailer) constructExpiry(code string, invite Invite, app *appContext, noSub bool) (*Message, error) {
|
||||
email := &Message{
|
||||
Subject: emailer.lang.InviteExpiry.get("title"),
|
||||
}
|
||||
var err error
|
||||
template := emailer.expiryValues(code, invite, app, noSub)
|
||||
if app.storage.customEmails.InviteExpiry.Enabled {
|
||||
content := templateEmail(
|
||||
app.storage.customEmails.InviteExpiry.Content,
|
||||
app.storage.customEmails.InviteExpiry.Variables,
|
||||
nil,
|
||||
template,
|
||||
)
|
||||
email, err = emailer.constructTemplate(email.Subject, content, app)
|
||||
} else {
|
||||
email.HTML, email.Text, email.Markdown, err = emailer.construct(app, "notifications", "expiry_", template)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return email, nil
|
||||
}
|
||||
|
||||
func (emailer *Emailer) createdValues(code, username, address string, invite Invite, app *appContext, noSub bool) map[string]interface{} {
|
||||
template := map[string]interface{}{
|
||||
"nameString": emailer.lang.Strings.get("name"),
|
||||
"addressString": emailer.lang.Strings.get("emailAddress"),
|
||||
"timeString": emailer.lang.UserCreated.get("time"),
|
||||
"notificationNotice": "",
|
||||
"code": "\"" + code + "\"",
|
||||
}
|
||||
if noSub {
|
||||
template["aUserWasCreated"] = emailer.lang.UserCreated.get("aUserWasCreated")
|
||||
empty := []string{"name", "address", "time"}
|
||||
for _, v := range empty {
|
||||
template[v] = "{" + v + "}"
|
||||
}
|
||||
} else {
|
||||
created := app.formatDatetime(invite.Created)
|
||||
var tplAddress string
|
||||
if app.config.Section("email").Key("no_username").MustBool(false) {
|
||||
tplAddress = "n/a"
|
||||
} else {
|
||||
tplAddress = address
|
||||
}
|
||||
template["aUserWasCreated"] = emailer.lang.UserCreated.template("aUserWasCreated", tmpl{"code": template["code"].(string)})
|
||||
template["name"] = username
|
||||
template["address"] = tplAddress
|
||||
template["time"] = created
|
||||
template["notificationNotice"] = emailer.lang.UserCreated.get("notificationNotice")
|
||||
}
|
||||
return template
|
||||
}
|
||||
|
||||
func (emailer *Emailer) constructCreated(code, username, address string, invite Invite, app *appContext, noSub bool) (*Message, error) {
|
||||
email := &Message{
|
||||
Subject: emailer.lang.UserCreated.get("title"),
|
||||
}
|
||||
template := emailer.createdValues(code, username, address, invite, app, noSub)
|
||||
var err error
|
||||
if app.storage.customEmails.UserCreated.Enabled {
|
||||
content := templateEmail(
|
||||
app.storage.customEmails.UserCreated.Content,
|
||||
app.storage.customEmails.UserCreated.Variables,
|
||||
nil,
|
||||
template,
|
||||
)
|
||||
email, err = emailer.constructTemplate(email.Subject, content, app)
|
||||
} else {
|
||||
email.HTML, email.Text, email.Markdown, err = emailer.construct(app, "notifications", "created_", template)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return email, nil
|
||||
}
|
||||
|
||||
func (emailer *Emailer) resetValues(pwr PasswordReset, app *appContext, noSub bool) map[string]interface{} {
|
||||
d, t, expiresIn := emailer.formatExpiry(pwr.Expiry, true, app.datePattern, app.timePattern)
|
||||
message := app.config.Section("email").Key("message").String()
|
||||
for _, key := range []string{"html", "text"} {
|
||||
fpath := app.config.Section("password_resets").Key("email_" + key).String()
|
||||
tpl, err := template.ParseFiles(fpath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
message := app.config.Section("messages").Key("message").String()
|
||||
template := map[string]interface{}{
|
||||
"someoneHasRequestedReset": emailer.lang.PasswordReset.get("someoneHasRequestedReset"),
|
||||
"ifItWasNotYou": emailer.lang.Strings.get("ifItWasNotYou"),
|
||||
"pinString": emailer.lang.PasswordReset.get("pin"),
|
||||
"link_reset": false,
|
||||
"message": "",
|
||||
"username": pwr.Username,
|
||||
"date": d,
|
||||
"time": t,
|
||||
"expiresInMinutes": expiresIn,
|
||||
}
|
||||
linkResetEnabled := app.config.Section("password_resets").Key("link_reset").MustBool(false)
|
||||
if linkResetEnabled {
|
||||
template["ifItWasYou"] = emailer.lang.PasswordReset.get("ifItWasYouLink")
|
||||
} else {
|
||||
template["ifItWasYou"] = emailer.lang.PasswordReset.get("ifItWasYou")
|
||||
}
|
||||
if noSub {
|
||||
template["helloUser"] = emailer.lang.Strings.get("helloUser")
|
||||
template["codeExpiry"] = emailer.lang.PasswordReset.get("codeExpiry")
|
||||
empty := []string{"pin"}
|
||||
for _, v := range empty {
|
||||
template[v] = "{" + v + "}"
|
||||
}
|
||||
var tplData bytes.Buffer
|
||||
err = tpl.Execute(&tplData, map[string]string{
|
||||
"username": pwr.Username,
|
||||
"expiry_date": d,
|
||||
"expiry_time": t,
|
||||
"expires_in": expiresIn,
|
||||
"pin": pwr.Pin,
|
||||
"message": message,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if key == "html" {
|
||||
email.html = tplData.String()
|
||||
} else {
|
||||
template["helloUser"] = emailer.lang.Strings.template("helloUser", tmpl{"username": pwr.Username})
|
||||
template["codeExpiry"] = emailer.lang.PasswordReset.template("codeExpiry", tmpl{"date": d, "time": t, "expiresInMinutes": expiresIn})
|
||||
inviteLink := app.config.Section("invite_emails").Key("url_base").String()
|
||||
if linkResetEnabled {
|
||||
if inviteLink != "" {
|
||||
// Strip /invite form end of this URL, ik its ugly.
|
||||
template["link_reset"] = true
|
||||
pinLink := fmt.Sprintf("%s/reset?pin=%s", strings.Replace(inviteLink, "/invite", "", 1), pwr.Pin)
|
||||
template["pin"] = pinLink
|
||||
// Only used in html email.
|
||||
template["pin_code"] = pwr.Pin
|
||||
} else {
|
||||
app.info.Println("Password Reset link disabled as no URL Base provided. Set in Settings > Invite Emails.")
|
||||
template["pin"] = pwr.Pin
|
||||
}
|
||||
} else {
|
||||
email.text = tplData.String()
|
||||
template["pin"] = pwr.Pin
|
||||
}
|
||||
template["message"] = message
|
||||
}
|
||||
return template
|
||||
}
|
||||
|
||||
func (emailer *Emailer) constructReset(pwr PasswordReset, app *appContext, noSub bool) (*Message, error) {
|
||||
email := &Message{
|
||||
Subject: app.config.Section("password_resets").Key("subject").MustString(emailer.lang.PasswordReset.get("title")),
|
||||
}
|
||||
template := emailer.resetValues(pwr, app, noSub)
|
||||
var err error
|
||||
if app.storage.customEmails.PasswordReset.Enabled {
|
||||
content := templateEmail(
|
||||
app.storage.customEmails.PasswordReset.Content,
|
||||
app.storage.customEmails.PasswordReset.Variables,
|
||||
nil,
|
||||
template,
|
||||
)
|
||||
email, err = emailer.constructTemplate(email.Subject, content, app)
|
||||
} else {
|
||||
email.HTML, email.Text, email.Markdown, err = emailer.construct(app, "password_resets", "email_", template)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return email, nil
|
||||
}
|
||||
|
||||
func (emailer *Emailer) constructDeleted(reason string, app *appContext) (*Email, error) {
|
||||
email := &Email{
|
||||
subject: app.config.Section("deletion").Key("subject").MustString("Your account was deleted - Jellyfin"),
|
||||
func (emailer *Emailer) deletedValues(reason string, app *appContext, noSub bool) map[string]interface{} {
|
||||
template := map[string]interface{}{
|
||||
"yourAccountWas": emailer.lang.UserDeleted.get("yourAccountWasDeleted"),
|
||||
"reasonString": emailer.lang.Strings.get("reason"),
|
||||
"message": "",
|
||||
}
|
||||
for _, key := range []string{"html", "text"} {
|
||||
fpath := app.config.Section("deletion").Key("email_" + key).String()
|
||||
tpl, err := template.ParseFiles(fpath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if noSub {
|
||||
empty := []string{"reason"}
|
||||
for _, v := range empty {
|
||||
template[v] = "{" + v + "}"
|
||||
}
|
||||
var tplData bytes.Buffer
|
||||
err = tpl.Execute(&tplData, map[string]string{
|
||||
"reason": reason,
|
||||
} else {
|
||||
template["reason"] = reason
|
||||
template["message"] = app.config.Section("messages").Key("message").String()
|
||||
}
|
||||
return template
|
||||
}
|
||||
|
||||
func (emailer *Emailer) constructDeleted(reason string, app *appContext, noSub bool) (*Message, error) {
|
||||
email := &Message{
|
||||
Subject: app.config.Section("deletion").Key("subject").MustString(emailer.lang.UserDeleted.get("title")),
|
||||
}
|
||||
var err error
|
||||
template := emailer.deletedValues(reason, app, noSub)
|
||||
if app.storage.customEmails.UserDeleted.Enabled {
|
||||
content := templateEmail(
|
||||
app.storage.customEmails.UserDeleted.Content,
|
||||
app.storage.customEmails.UserDeleted.Variables,
|
||||
nil,
|
||||
template,
|
||||
)
|
||||
email, err = emailer.constructTemplate(email.Subject, content, app)
|
||||
} else {
|
||||
email.HTML, email.Text, email.Markdown, err = emailer.construct(app, "deletion", "email_", template)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return email, nil
|
||||
}
|
||||
|
||||
func (emailer *Emailer) disabledValues(reason string, app *appContext, noSub bool) map[string]interface{} {
|
||||
template := map[string]interface{}{
|
||||
"yourAccountWas": emailer.lang.UserDisabled.get("yourAccountWasDisabled"),
|
||||
"reasonString": emailer.lang.Strings.get("reason"),
|
||||
"message": "",
|
||||
}
|
||||
if noSub {
|
||||
empty := []string{"reason"}
|
||||
for _, v := range empty {
|
||||
template[v] = "{" + v + "}"
|
||||
}
|
||||
} else {
|
||||
template["reason"] = reason
|
||||
template["message"] = app.config.Section("messages").Key("message").String()
|
||||
}
|
||||
return template
|
||||
}
|
||||
|
||||
func (emailer *Emailer) constructDisabled(reason string, app *appContext, noSub bool) (*Message, error) {
|
||||
email := &Message{
|
||||
Subject: app.config.Section("disable_enable").Key("subject_disabled").MustString(emailer.lang.UserDisabled.get("title")),
|
||||
}
|
||||
var err error
|
||||
template := emailer.disabledValues(reason, app, noSub)
|
||||
if app.storage.customEmails.UserDisabled.Enabled {
|
||||
content := templateEmail(
|
||||
app.storage.customEmails.UserDisabled.Content,
|
||||
app.storage.customEmails.UserDisabled.Variables,
|
||||
nil,
|
||||
template,
|
||||
)
|
||||
email, err = emailer.constructTemplate(email.Subject, content, app)
|
||||
} else {
|
||||
email.HTML, email.Text, email.Markdown, err = emailer.construct(app, "disable_enable", "disabled_", template)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return email, nil
|
||||
}
|
||||
|
||||
func (emailer *Emailer) enabledValues(reason string, app *appContext, noSub bool) map[string]interface{} {
|
||||
template := map[string]interface{}{
|
||||
"yourAccountWas": emailer.lang.UserEnabled.get("yourAccountWasEnabled"),
|
||||
"reasonString": emailer.lang.Strings.get("reason"),
|
||||
"message": "",
|
||||
}
|
||||
if noSub {
|
||||
empty := []string{"reason"}
|
||||
for _, v := range empty {
|
||||
template[v] = "{" + v + "}"
|
||||
}
|
||||
} else {
|
||||
template["reason"] = reason
|
||||
template["message"] = app.config.Section("messages").Key("message").String()
|
||||
}
|
||||
return template
|
||||
}
|
||||
|
||||
func (emailer *Emailer) constructEnabled(reason string, app *appContext, noSub bool) (*Message, error) {
|
||||
email := &Message{
|
||||
Subject: app.config.Section("disable_enable").Key("subject_enabled").MustString(emailer.lang.UserEnabled.get("title")),
|
||||
}
|
||||
var err error
|
||||
template := emailer.enabledValues(reason, app, noSub)
|
||||
if app.storage.customEmails.UserEnabled.Enabled {
|
||||
content := templateEmail(
|
||||
app.storage.customEmails.UserEnabled.Content,
|
||||
app.storage.customEmails.UserEnabled.Variables,
|
||||
nil,
|
||||
template,
|
||||
)
|
||||
email, err = emailer.constructTemplate(email.Subject, content, app)
|
||||
} else {
|
||||
email.HTML, email.Text, email.Markdown, err = emailer.construct(app, "disable_enable", "enabled_", template)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return email, nil
|
||||
}
|
||||
|
||||
func (emailer *Emailer) welcomeValues(username string, expiry time.Time, app *appContext, noSub bool, custom bool) map[string]interface{} {
|
||||
template := map[string]interface{}{
|
||||
"welcome": emailer.lang.WelcomeEmail.get("welcome"),
|
||||
"youCanLoginWith": emailer.lang.WelcomeEmail.get("youCanLoginWith"),
|
||||
"jellyfinURLString": emailer.lang.WelcomeEmail.get("jellyfinURL"),
|
||||
"usernameString": emailer.lang.Strings.get("username"),
|
||||
"message": "",
|
||||
"yourAccountWillExpire": "",
|
||||
}
|
||||
if noSub {
|
||||
empty := []string{"jellyfinURL", "username", "yourAccountWillExpire"}
|
||||
for _, v := range empty {
|
||||
template[v] = "{" + v + "}"
|
||||
}
|
||||
} else {
|
||||
template["jellyfinURL"] = app.config.Section("jellyfin").Key("public_server").String()
|
||||
template["username"] = username
|
||||
template["message"] = app.config.Section("messages").Key("message").String()
|
||||
exp := app.formatDatetime(expiry)
|
||||
if !expiry.IsZero() {
|
||||
if custom {
|
||||
template["yourAccountWillExpire"] = exp
|
||||
} else if !expiry.IsZero() {
|
||||
template["yourAccountWillExpire"] = emailer.lang.WelcomeEmail.template("yourAccountWillExpire", tmpl{
|
||||
"date": exp,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return template
|
||||
}
|
||||
|
||||
func (emailer *Emailer) constructWelcome(username string, expiry time.Time, app *appContext, noSub bool) (*Message, error) {
|
||||
email := &Message{
|
||||
Subject: app.config.Section("welcome_email").Key("subject").MustString(emailer.lang.WelcomeEmail.get("title")),
|
||||
}
|
||||
var err error
|
||||
var template map[string]interface{}
|
||||
if app.storage.customEmails.WelcomeEmail.Enabled {
|
||||
template = emailer.welcomeValues(username, expiry, app, noSub, true)
|
||||
} else {
|
||||
template = emailer.welcomeValues(username, expiry, app, noSub, false)
|
||||
}
|
||||
if noSub {
|
||||
template["yourAccountWillExpire"] = emailer.lang.WelcomeEmail.template("yourAccountWillExpire", tmpl{
|
||||
"date": "{yourAccountWillExpire}",
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if key == "html" {
|
||||
email.html = tplData.String()
|
||||
} else {
|
||||
email.text = tplData.String()
|
||||
}
|
||||
}
|
||||
if app.storage.customEmails.WelcomeEmail.Enabled {
|
||||
content := templateEmail(
|
||||
app.storage.customEmails.WelcomeEmail.Content,
|
||||
app.storage.customEmails.WelcomeEmail.Variables,
|
||||
app.storage.customEmails.WelcomeEmail.Conditionals,
|
||||
template,
|
||||
)
|
||||
email, err = emailer.constructTemplate(email.Subject, content, app)
|
||||
} else {
|
||||
email.HTML, email.Text, email.Markdown, err = emailer.construct(app, "welcome_email", "email_", template)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return email, nil
|
||||
}
|
||||
|
||||
func (emailer *Emailer) userExpiredValues(app *appContext, noSub bool) map[string]interface{} {
|
||||
template := map[string]interface{}{
|
||||
"yourAccountHasExpired": emailer.lang.UserExpired.get("yourAccountHasExpired"),
|
||||
"contactTheAdmin": emailer.lang.UserExpired.get("contactTheAdmin"),
|
||||
"message": "",
|
||||
}
|
||||
if !noSub {
|
||||
template["message"] = app.config.Section("messages").Key("message").String()
|
||||
}
|
||||
return template
|
||||
}
|
||||
|
||||
func (emailer *Emailer) constructUserExpired(app *appContext, noSub bool) (*Message, error) {
|
||||
email := &Message{
|
||||
Subject: app.config.Section("user_expiry").Key("subject").MustString(emailer.lang.UserExpired.get("title")),
|
||||
}
|
||||
var err error
|
||||
template := emailer.userExpiredValues(app, noSub)
|
||||
if app.storage.customEmails.UserExpired.Enabled {
|
||||
content := templateEmail(
|
||||
app.storage.customEmails.UserExpired.Content,
|
||||
app.storage.customEmails.UserExpired.Variables,
|
||||
nil,
|
||||
template,
|
||||
)
|
||||
email, err = emailer.constructTemplate(email.Subject, content, app)
|
||||
} else {
|
||||
email.HTML, email.Text, email.Markdown, err = emailer.construct(app, "user_expiry", "email_", template)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return email, nil
|
||||
}
|
||||
|
||||
// calls the send method in the underlying emailClient.
|
||||
func (emailer *Emailer) send(address string, email *Email) error {
|
||||
return emailer.sender.send(address, emailer.fromName, emailer.fromAddr, email)
|
||||
func (emailer *Emailer) send(email *Message, address ...string) error {
|
||||
return emailer.sender.Send(emailer.fromName, emailer.fromAddr, email, address...)
|
||||
}
|
||||
|
||||
func (app *appContext) sendByID(email *Message, ID ...string) error {
|
||||
for _, id := range ID {
|
||||
var err error
|
||||
if tgChat, ok := app.storage.telegram[id]; ok && tgChat.Contact && telegramEnabled {
|
||||
err = app.telegram.Send(email, tgChat.ChatID)
|
||||
} else if address, ok := app.storage.emails[id]; ok {
|
||||
err = app.email.send(email, address.(string))
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (app *appContext) getAddressOrName(jfID string) string {
|
||||
if tgChat, ok := app.storage.telegram[jfID]; ok && tgChat.Contact && telegramEnabled {
|
||||
return "@" + tgChat.Username
|
||||
}
|
||||
if addr, ok := app.storage.emails[jfID]; ok {
|
||||
return addr.(string)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
37
external.go
Normal file
@@ -0,0 +1,37 @@
|
||||
// +build external
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const binaryType = "external"
|
||||
|
||||
var localFS fs.FS
|
||||
var langFS fs.FS
|
||||
|
||||
// When using os.DirFS, even on Windows the separator seems to be '/'.
|
||||
// func FSJoin(elem ...string) string { return filepath.Join(elem...) }
|
||||
func FSJoin(elem ...string) string {
|
||||
sep := "/"
|
||||
if strings.Contains(elem[0], "\\") {
|
||||
sep = "\\"
|
||||
}
|
||||
path := ""
|
||||
for _, el := range elem {
|
||||
path += el + sep
|
||||
}
|
||||
return strings.TrimSuffix(path, sep)
|
||||
}
|
||||
|
||||
func loadFilesystems() {
|
||||
log.Println("Using external storage")
|
||||
executable, _ := os.Executable()
|
||||
localFS = os.DirFS(filepath.Join(filepath.Dir(executable), "data"))
|
||||
langFS = os.DirFS(filepath.Join(filepath.Dir(executable), "data", "lang"))
|
||||
}
|
||||
48
go.mod
@@ -1,54 +1,50 @@
|
||||
module github.com/hrfee/jfa-go
|
||||
|
||||
go 1.14
|
||||
go 1.16
|
||||
|
||||
replace github.com/hrfee/jfa-go/docs => ./docs
|
||||
|
||||
replace github.com/hrfee/jfa-go/jfapi => ./jfapi
|
||||
|
||||
replace github.com/hrfee/jfa-go/common => ./common
|
||||
|
||||
replace github.com/hrfee/jfa-go/ombi => ./ombi
|
||||
|
||||
replace github.com/hrfee/jfa-go/logger => ./logger
|
||||
|
||||
require (
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/fatih/color v1.10.0
|
||||
github.com/fsnotify/fsnotify v1.4.9
|
||||
github.com/gin-contrib/pprof v1.3.0
|
||||
github.com/gin-contrib/static v0.0.0-20200916080430-d45d9a37d28e
|
||||
github.com/gin-gonic/gin v1.6.3
|
||||
github.com/go-chi/chi v4.1.2+incompatible // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/spec v0.20.0 // indirect
|
||||
github.com/go-openapi/spec v0.20.3 // indirect
|
||||
github.com/go-openapi/swag v0.19.15 // indirect
|
||||
github.com/go-playground/validator/v10 v10.4.1 // indirect
|
||||
github.com/gofrs/uuid v3.3.0+incompatible // indirect
|
||||
github.com/golang/protobuf v1.4.3
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible // indirect
|
||||
github.com/golang/protobuf v1.4.3 // indirect
|
||||
github.com/gomarkdown/markdown v0.0.0-20210408062403-ad838ccf8cdd
|
||||
github.com/google/uuid v1.1.2 // indirect
|
||||
github.com/hrfee/jfa-go/common v0.0.0-20201112212552-b6f3cd7c1f71
|
||||
github.com/hrfee/jfa-go/common v0.0.0-20210105184019-fdc97b4e86cc
|
||||
github.com/hrfee/jfa-go/docs v0.0.0-20201112212552-b6f3cd7c1f71
|
||||
github.com/hrfee/jfa-go/jfapi v0.0.0-20201112212552-b6f3cd7c1f71
|
||||
github.com/hrfee/jfa-go/logger v0.0.0-00010101000000-000000000000
|
||||
github.com/hrfee/jfa-go/ombi v0.0.0-20201112212552-b6f3cd7c1f71
|
||||
github.com/jordan-wright/email v4.0.1-0.20200917010138-e1c00e156980+incompatible
|
||||
github.com/json-iterator/go v1.1.10 // indirect
|
||||
github.com/knz/strtime v0.0.0-20200924090105-187c67f2bf5e
|
||||
github.com/hrfee/mediabrowser v0.3.3
|
||||
github.com/itchyny/timefmt-go v0.1.2
|
||||
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible
|
||||
github.com/lithammer/shortuuid/v3 v3.0.4
|
||||
github.com/logrusorgru/aurora/v3 v3.0.0
|
||||
github.com/mailgun/mailgun-go/v4 v4.3.0
|
||||
github.com/mailru/easyjson v0.7.6 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||
github.com/pdrum/swagger-automation v0.0.0-20190629163613-c8c7c80ba858
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/mailgun/mailgun-go/v4 v4.5.1
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/smartystreets/goconvey v1.6.4 // indirect
|
||||
github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14
|
||||
github.com/swaggo/gin-swagger v1.3.0
|
||||
github.com/swaggo/swag v1.7.0 // indirect
|
||||
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
|
||||
github.com/ugorji/go v1.2.0 // indirect
|
||||
github.com/urfave/cli/v2 v2.3.0 // indirect
|
||||
github.com/writeas/go-strip-markdown v2.0.1+incompatible
|
||||
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9 // indirect
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b // indirect
|
||||
golang.org/x/text v0.3.4 // indirect
|
||||
golang.org/x/tools v0.0.0-20210104081019-d8d6ddbec6ee // indirect
|
||||
golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c // indirect
|
||||
golang.org/x/sys v0.0.0-20210331175145-43e1dd70ce54 // indirect
|
||||
golang.org/x/tools v0.1.0 // indirect
|
||||
google.golang.org/protobuf v1.25.0 // indirect
|
||||
gopkg.in/ini.v1 v1.62.0
|
||||
)
|
||||
|
||||
274
go.sum
@@ -1,4 +1,6 @@
|
||||
cloud.google.com/go v0.26.0 h1:e0WKqKTd5BnrG8aKH3J3h+QvEIQtSUcf2n5UZ5ZgLtQ=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
||||
@@ -9,28 +11,38 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgrijalva/jwt-go v1.0.2 h1:KPldsxuKGsS2FPWsNeg9ZO18aCrGKujPoWXn2yo+KQM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk=
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473 h1:4cmBvAEBNJaGARUEs3/suWRyfyBfhf7I60WBZq+bv2w=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ=
|
||||
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64=
|
||||
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A=
|
||||
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg=
|
||||
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQDg5gKsWoLBOB0n+ZW8s599zru8FJ2/Y=
|
||||
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0=
|
||||
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
|
||||
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gin-contrib/gzip v0.0.1 h1:ezvKOL6jH+jlzdHNE4h9h8q8uMpDQjyl0NN0Jd7jozc=
|
||||
github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w=
|
||||
github.com/gin-contrib/pprof v1.3.0 h1:G9eK6HnbkSqDZBYbzG4wrjCsA4e+cvYAHUZw6W+W9K0=
|
||||
github.com/gin-contrib/pprof v1.3.0/go.mod h1:waMjT1H9b179t3CxuG1cV3DHpga6ybizwfBaM5OXaB0=
|
||||
@@ -38,10 +50,6 @@ github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NB
|
||||
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-contrib/static v0.0.0-20191128031702-f81c604d8ac2 h1:xLG16iua01X7Gzms9045s2Y2niNpvSY/Zb1oBwgNYZY=
|
||||
github.com/gin-contrib/static v0.0.0-20191128031702-f81c604d8ac2/go.mod h1:VhW/Ch/3FhimwZb8Oj+qJmdMmoB8r7lmJ5auRjm50oQ=
|
||||
github.com/gin-contrib/static v0.0.0-20200815103939-31fb0c56a3d1 h1:plQYoJeO9lI8Ag0xZy7dDF8FMwIOHsQylKjcclknvIc=
|
||||
github.com/gin-contrib/static v0.0.0-20200815103939-31fb0c56a3d1/go.mod h1:VhW/Ch/3FhimwZb8Oj+qJmdMmoB8r7lmJ5auRjm50oQ=
|
||||
github.com/gin-contrib/static v0.0.0-20200916080430-d45d9a37d28e h1:8bZpGwoPxkaivQPrAbWl+7zjjUcbFUnYp7yQcx2r2N0=
|
||||
github.com/gin-contrib/static v0.0.0-20200916080430-d45d9a37d28e/go.mod h1:VhW/Ch/3FhimwZb8Oj+qJmdMmoB8r7lmJ5auRjm50oQ=
|
||||
github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y=
|
||||
@@ -50,52 +58,31 @@ github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmC
|
||||
github.com/gin-gonic/gin v1.6.2/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
|
||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
github.com/go-chi/chi v4.0.0+incompatible h1:SiLLEDyAkqNnw+T/uDTf3aFB9T4FTrwMpuYrgaRcnW4=
|
||||
github.com/go-chi/chi v4.0.0+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
|
||||
github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec=
|
||||
github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
|
||||
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
||||
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
|
||||
github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
|
||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
|
||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
|
||||
github.com/go-openapi/jsonreference v0.19.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
|
||||
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
|
||||
github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o=
|
||||
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
|
||||
github.com/go-openapi/jsonreference v0.19.4 h1:3Vw+rh13uq2JFNxgnMTGE1rnoieU9FmyE1gvnyylsYg=
|
||||
github.com/go-openapi/jsonreference v0.19.4/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
|
||||
github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM=
|
||||
github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
|
||||
github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
|
||||
github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo=
|
||||
github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
|
||||
github.com/go-openapi/spec v0.19.9 h1:9z9cbFuZJ7AcvOHKIY+f6Aevb4vObNDkTEyoMfO7rAc=
|
||||
github.com/go-openapi/spec v0.19.9/go.mod h1:vqK/dIdLGCosfvYsQV3WfC7N3TiZSnGY2RZKoFK7X28=
|
||||
github.com/go-openapi/spec v0.19.10 h1:pcNevfYytLaOQuTju0wm6OqcqU/E/pRwuSGigrLTI28=
|
||||
github.com/go-openapi/spec v0.19.10/go.mod h1:vqK/dIdLGCosfvYsQV3WfC7N3TiZSnGY2RZKoFK7X28=
|
||||
github.com/go-openapi/spec v0.19.12 h1:OO9WrvhDwtiMY/Opr1j1iFZzirI3JW4/bxNFRcntAr4=
|
||||
github.com/go-openapi/spec v0.19.12/go.mod h1:gwrgJS15eCUgjLpMjBJmbZezCsw88LmgeEip0M63doA=
|
||||
github.com/go-openapi/spec v0.19.13 h1:AcZVcWsrfW7LqyHKVbTZYpFF7jQcMxmAsWrw2p/b9ew=
|
||||
github.com/go-openapi/spec v0.19.13/go.mod h1:gwrgJS15eCUgjLpMjBJmbZezCsw88LmgeEip0M63doA=
|
||||
github.com/go-openapi/spec v0.19.14 h1:r4fbYFo6N4ZelmSX8G6p+cv/hZRXzcuqQIADGT1iNKM=
|
||||
github.com/go-openapi/spec v0.19.14/go.mod h1:gwrgJS15eCUgjLpMjBJmbZezCsw88LmgeEip0M63doA=
|
||||
github.com/go-openapi/spec v0.20.0 h1:HGLc8AJ7ynOxwv0Lq4TsnwLsWMawHAYiJIFzbcML86I=
|
||||
github.com/go-openapi/spec v0.20.0/go.mod h1:+81FIL1JwC5P3/Iuuozq3pPE9dXdIEGxFutcFKaVbmU=
|
||||
github.com/go-openapi/spec v0.20.3 h1:uH9RQ6vdyPSs2pSy9fL8QPspDF2AMIMPtmK5coSSjtQ=
|
||||
github.com/go-openapi/spec v0.20.3/go.mod h1:gG4F8wdEDN+YPBMVnzE85Rbhf+Th2DTvA9nFPQ5AYEg=
|
||||
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
||||
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.9 h1:1IxuqvBUU3S2Bi4YC7tlP9SJF1gVpCvqN0T2Qof4azE=
|
||||
github.com/go-openapi/swag v0.19.9/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY=
|
||||
github.com/go-openapi/swag v0.19.10 h1:A1SWXruroGP15P1sOiegIPbaKio+G9N5TwWTFaVPmAU=
|
||||
github.com/go-openapi/swag v0.19.10/go.mod h1:Uc0gKkdR+ojzsEpjh39QChyu92vPgIr72POcgHMAgSY=
|
||||
github.com/go-openapi/swag v0.19.11 h1:RFTu/dlFySpyVvJDfp/7674JY4SDglYWKztbiIGFpmc=
|
||||
github.com/go-openapi/swag v0.19.11/go.mod h1:Uc0gKkdR+ojzsEpjh39QChyu92vPgIr72POcgHMAgSY=
|
||||
github.com/go-openapi/swag v0.19.12 h1:Bc0bnY2c3AoF7Gc+IMIAQQsD8fLHjHpc19wXvYuayQI=
|
||||
github.com/go-openapi/swag v0.19.12/go.mod h1:eFdyEBkTdoAf/9RXBvj4cr1nH7GD8Kzo5HTt47gr72M=
|
||||
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
|
||||
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
|
||||
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||
@@ -103,21 +90,18 @@ github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTM
|
||||
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
|
||||
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
|
||||
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
||||
github.com/go-playground/validator/v10 v10.3.0 h1:nZU+7q+yJoFmwvNgv/LnPUkwPal62+b2xXj0AU1Es7o=
|
||||
github.com/go-playground/validator/v10 v10.3.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
||||
github.com/go-playground/validator/v10 v10.4.0 h1:72qIR/m8ybvL8L5TIyfgrigqkrw7kVYAvjEvpT85l70=
|
||||
github.com/go-playground/validator/v10 v10.4.0/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
|
||||
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||
github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible h1:2cauKuaELYAEARXRkq2LrJ0yDDv1rW7+wrTEdVL3uaU=
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1 h1:G5FRp8JnTd7RQH5kemVNlMeyXQAztQ3mOWV95KxsXH8=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
@@ -125,174 +109,149 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/gomarkdown/markdown v0.0.0-20210408062403-ad838ccf8cdd h1:0b8AqsWQb6A0jjx80UXLG/uMTXQkGD0IGuXWqsrNz1M=
|
||||
github.com/gomarkdown/markdown v0.0.0-20210408062403-ad838ccf8cdd/go.mod h1:aii0r/K0ZnHv7G0KF7xy1v0A7s2Ljrb5byB7MO5p6TU=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/jordan-wright/email v0.0.0-20200602115436-fd8a7622303e h1:OGunVjqY7y4U4laftpEHv+mvZBlr7UGimJXKEGQtg48=
|
||||
github.com/jordan-wright/email v0.0.0-20200602115436-fd8a7622303e/go.mod h1:Fy2gCFfZhay8jplf/Csj6cyH/oshQTkLQYZbKkcV+SY=
|
||||
github.com/jordan-wright/email v4.0.1-0.20200917010138-e1c00e156980+incompatible h1:CL0ooBNfbNyJTJATno+m0h+zM5bW6v7fKlboKUGP/dI=
|
||||
github.com/jordan-wright/email v4.0.1-0.20200917010138-e1c00e156980+incompatible/go.mod h1:1c7szIrayyPPB/987hsnvNzLushdWf4o/79s3P08L8A=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/hrfee/mediabrowser v0.3.3 h1:7E05uiol8hh2ytKn3WVLrUIvHAyifYEIy3Y5qtuNh8I=
|
||||
github.com/hrfee/mediabrowser v0.3.3/go.mod h1:PnHZbdxmbv1wCVdAQyM7nwPwpVj9fdKx2EcET7sAk+U=
|
||||
github.com/itchyny/timefmt-go v0.1.2 h1:q0Xa4P5it6K6D7ISsbLAMwx1PnWlixDcJL6/sFs93Hs=
|
||||
github.com/itchyny/timefmt-go v0.1.2/go.mod h1:0osSSCQSASBJMsIZnhAaF1C2fCBTJZXrnj37mG8/c+A=
|
||||
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible h1:jdpOPRN1zP63Td1hDQbZW73xKmzDvZHzVdNYxhnTMDA=
|
||||
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible/go.mod h1:1c7szIrayyPPB/987hsnvNzLushdWf4o/79s3P08L8A=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/knz/strtime v0.0.0-20200318182718-be999391ffa9 h1:GQE1iatYDRrIidq4Zf/9ZzKWyrTk2sXOYc1JADbkAjQ=
|
||||
github.com/knz/strtime v0.0.0-20200318182718-be999391ffa9/go.mod h1:4ZxfWkxwtc7dBeifERVVWRy9F9rTU9p0yCDgeCtlius=
|
||||
github.com/knz/strtime v0.0.0-20200924090105-187c67f2bf5e h1:ViPE0JEOvtw5I0EGUiFSr2VNKGNU+3oBT+oHbDXHbxk=
|
||||
github.com/knz/strtime v0.0.0-20200924090105-187c67f2bf5e/go.mod h1:4ZxfWkxwtc7dBeifERVVWRy9F9rTU9p0yCDgeCtlius=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.5 h1:hyz3dwM5QLc1Rfoz4FuWJQG5BN7tc6K1MndAUnGpQr4=
|
||||
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8bbnE7CX5OEgg=
|
||||
github.com/labstack/echo v3.3.10+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s=
|
||||
github.com/labstack/gommon v0.2.9 h1:heVeuAYtevIQVYkGj6A41dtfT91LrvFG220lavpWhrU=
|
||||
github.com/labstack/gommon v0.2.9/go.mod h1:E8ZTmW9vw5az5/ZyHWCp0Lw4OH2ecsaBP1C/NKavGG4=
|
||||
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
|
||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/lithammer/shortuuid v1.0.0 h1:kdcbvjGVEgqeVeDIRtnANOi/F6ftbKrtbxY+cjQmK1Q=
|
||||
github.com/lithammer/shortuuid v3.0.0+incompatible h1:NcD0xWW/MZYXEHa6ITy6kaXN5nwm/V115vj2YXfhS0w=
|
||||
github.com/lithammer/shortuuid/v3 v3.0.4 h1:uj4xhotfY92Y1Oa6n6HUiFn87CdoEHYUlTy0+IgbLrs=
|
||||
github.com/lithammer/shortuuid/v3 v3.0.4/go.mod h1:RviRjexKqIzx/7r1peoAITm6m7gnif/h+0zmolKJjzw=
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
|
||||
github.com/logrusorgru/aurora/v3 v3.0.0 h1:R6zcoZZbvVcGMvDCKo45A9U/lzYyzl5NfYIvznmDfE4=
|
||||
github.com/logrusorgru/aurora/v3 v3.0.0/go.mod h1:vsR12bk5grlLvLXAYrBsb5Oc/N+LxAlxggSjiwMnCUc=
|
||||
github.com/mailgun/mailgun-go v1.1.1 h1:mjMcm4qz+SbjAYbGJ6DKROViKtO5S0YjpuOUxQfdr2A=
|
||||
github.com/mailgun/mailgun-go v2.0.0+incompatible h1:0FoRHWwMUctnd8KIR3vtZbqdfjpIMxOZgcSa51s8F8o=
|
||||
github.com/mailgun/mailgun-go/v4 v4.1.3 h1:KLa5EZaOMMeyvY/lfAhWxv9ealB3mtUsMz0O9XmTtP0=
|
||||
github.com/mailgun/mailgun-go/v4 v4.1.3/go.mod h1:R9kHUQBptF4iSEjhriCQizplCDwrnDShy8w/iPiOfaM=
|
||||
github.com/mailgun/mailgun-go/v4 v4.2.0 h1:AAt7TwR98Pog7zAYK61SW7ikykFFmCovtix3vvS2cK4=
|
||||
github.com/mailgun/mailgun-go/v4 v4.2.0/go.mod h1:R9kHUQBptF4iSEjhriCQizplCDwrnDShy8w/iPiOfaM=
|
||||
github.com/mailgun/mailgun-go/v4 v4.3.0 h1:9nAF7LI3k6bfDPbMZQMMl63Q8/vs+dr1FUN8eR1XMhk=
|
||||
github.com/mailgun/mailgun-go/v4 v4.3.0/go.mod h1:fWuBI2iaS/pSSyo6+EBpHjatQO3lV8onwqcRy7joSJI=
|
||||
github.com/mailgun/mailgun-go/v4 v4.5.1 h1:XrQQ/ZgqFvINRKy+eBqowLl7k3pQO6OCLpKphliMOFs=
|
||||
github.com/mailgun/mailgun-go/v4 v4.5.1/go.mod h1:FJlF9rI5cQT+mrwujtJjPMbIVy3Ebor9bKTVsJ0QU40=
|
||||
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM=
|
||||
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
|
||||
github.com/mailru/easyjson v0.7.2 h1:V9ecaZWDYm7v9uJ15RZD6DajMu5sE0hdep0aoDwT9g4=
|
||||
github.com/mailru/easyjson v0.7.2/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mailru/easyjson v0.7.3 h1:M6wcO9gFHCIPynXGu4iA+NMs//FCgFUWR2jxqV3/+Xk=
|
||||
github.com/mailru/easyjson v0.7.3/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
|
||||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/pdrum/swagger-automation v0.0.0-20190629163613-c8c7c80ba858 h1:lgbJiJQx8bXo+eM88AFdd0VxUvaTLzCBXpK+H9poJ+Y=
|
||||
github.com/pdrum/swagger-automation v0.0.0-20190629163613-c8c7c80ba858/go.mod h1:y02HeaN0visd95W6cEX2NXDv5sCwyqfzucWTdDGEwYY=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14 h1:PyYN9JH5jY9j6av01SpfRMb+1DWg/i3MbGOKPxJ2wjM=
|
||||
github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E=
|
||||
github.com/swaggo/gin-swagger v1.2.0 h1:YskZXEiv51fjOMTsXrOetAjrMDfFaXD79PEoQBOe2W0=
|
||||
github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05Nn6vPhc7OI=
|
||||
github.com/swaggo/gin-swagger v1.3.0 h1:eOmp7r57oUgZPw2dJOjcGNMse9cvXcI4tTqBcnZtPsI=
|
||||
github.com/swaggo/gin-swagger v1.3.0/go.mod h1:oy1BRA6WvgtCp848lhxce7BnWH4C8Bxa0m5SkWx+cS0=
|
||||
github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y=
|
||||
github.com/swaggo/swag v1.6.7 h1:e8GC2xDllJZr3omJkm9YfmK0Y56+rMO3cg0JBKNz09s=
|
||||
github.com/swaggo/swag v1.6.7/go.mod h1:xDhTyuFIujYiN3DKWC/H/83xcfHp+UE/IzWWampG7Zc=
|
||||
github.com/swaggo/swag v1.6.8 h1:z3ZNcpJs/NLMpZcKqXUsBELmmY2Ocy09JXKx5gu3L4M=
|
||||
github.com/swaggo/swag v1.6.8/go.mod h1:a0IpNeMfGidNOcm2TsqODUh9JHdHu3kxDA0UlGbBKjI=
|
||||
github.com/swaggo/swag v1.6.9 h1:BukKRwZjnEcUxQt7Xgfrt9fpav0hiWw9YimdNO9wssw=
|
||||
github.com/swaggo/swag v1.6.9/go.mod h1:a0IpNeMfGidNOcm2TsqODUh9JHdHu3kxDA0UlGbBKjI=
|
||||
github.com/swaggo/swag v1.7.0 h1:5bCA/MTLQoIqDXXyHfOpMeDvL9j68OY/udlK4pQoo4E=
|
||||
github.com/swaggo/swag v1.7.0/go.mod h1:BdPIL73gvS9NBsdi7M1JOxLvlbfvNRaBP8m6WT6Aajo=
|
||||
github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
|
||||
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0=
|
||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go v1.1.9 h1:SObrQTaSuP8WOv2WNCj8gECiNSJIUvk3Q7N26c96Gws=
|
||||
github.com/ugorji/go v1.1.9/go.mod h1:chLrngdsg43geAaeId+nXO57YsDdl5OZqd/QtBiD19g=
|
||||
github.com/ugorji/go v1.1.13/go.mod h1:jxau1n+/wyTGLQoCkjok9r5zFa/FxT6eI5HiHKQszjc=
|
||||
github.com/ugorji/go v1.2.0 h1:6eXlzYLLwZwXroJx9NyqbYcbv/d93twiOzQLDewE6qM=
|
||||
github.com/ugorji/go v1.2.0/go.mod h1:1ny++pKMXhLWrwWV5Nf+CbOuZJhMoaFD+0GMFfd8fEc=
|
||||
github.com/ugorji/go/codec v0.0.0-20181022190402-e5e69e061d4f/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2tfCQDUqRd8fI=
|
||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/ugorji/go/codec v1.1.9 h1:J/7hhpkQwgypRNvaeh/T5gzJ2gEI/l8S3qyRrdEa1fA=
|
||||
github.com/ugorji/go/codec v1.1.9/go.mod h1:+SWgpdqOgdW5sBaiDfkHilQ1SxQ1hBkq/R+kHfL7Suo=
|
||||
github.com/ugorji/go/codec v1.1.13/go.mod h1:oNVt3Dq+FO91WNQ/9JnHKQP2QJxTzoN7wCBFCq1OeuU=
|
||||
github.com/ugorji/go/codec v1.2.0 h1:As6RccOIlbm9wHuWYMlB30dErcI+4WiKWsYsmPkyrUw=
|
||||
github.com/ugorji/go/codec v1.2.0/go.mod h1:dXvG35r7zTX6QImXOSFhGMmKtX+wJ7VTWzGvYQGIjBs=
|
||||
github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k=
|
||||
github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
|
||||
github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4=
|
||||
github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
|
||||
github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
|
||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=
|
||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/writeas/go-strip-markdown v2.0.1+incompatible h1:IIqxTM5Jr7RzhigcL6FkrCNfXkvbR+Nbu1ls48pXYcw=
|
||||
github.com/writeas/go-strip-markdown v2.0.1+incompatible/go.mod h1:Rsyu10ZhbEK9pXdk8V6MVnZmTzRG0alMNLMwa0J01fE=
|
||||
github.com/yuin/goldmark v1.2.1 h1:ruQGxdhGHe7FWOJPT0mKs5+pD2Xs1Bm/kdGlHO04FmM=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
golang.org/dl v0.0.0-20190829154251-82a15e2f2ead h1:jeP6FgaSLNTMP+Yri3qjlACywQLye+huGLmNGhBzm6k=
|
||||
golang.org/dl v0.0.0-20190829154251-82a15e2f2ead/go.mod h1:IUMfjQLJQd4UTqG1Z90tenwKoCX93Gn3MAQJMOSBsDQ=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9 h1:umElSU9WZirRdgu2yFHY0ayQkEnKiOC1TtM3fWXFnoU=
|
||||
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4 h1:c2HOrn5iMezYjSlGPncknSEr/8x5LELb/ilJbXi9DEA=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3 h1:XQyxROzUlZH+WIQwySDgnISgOivlhjIEwaQaJEJrrN0=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -305,110 +264,73 @@ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||
golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200923182212-328152dc79b1 h1:Iu68XRPd67wN4aRGGWwwq6bZo/25jR6uu52l/j2KkUE=
|
||||
golang.org/x/net v0.0.0-20200923182212-328152dc79b1/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200927032502-5d4f70055728 h1:5wtQIAulKU5AbLQOkjxl32UufnIOqgBX72pS0AV14H0=
|
||||
golang.org/x/net v0.0.0-20200927032502-5d4f70055728/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 h1:wBouT66WTYFXdxfVdz9sVWARVd/2vfGcmI45D2gj45M=
|
||||
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0 h1:5kGOVHlq0euqwzgTC9Vu15p6fV1Wi0ArVi8da2urnVg=
|
||||
golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102 h1:42cLlJJdEh+ySyeUUbEQ5bsTiq8voBeTuweGVkY6Puw=
|
||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c h1:KHUzaHIpjWVlVVNh65G3hhuj3KB1HnjY6Cq5cTvRQT8=
|
||||
golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1 h1:sIky/MyNRSHTrdxfsiUSS4WIAMvInbeXljJz+jDjeYE=
|
||||
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed h1:J22ig1FUekjjkmZUM7pTKixYm8DvrYsvrBZdunYeIuQ=
|
||||
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200929083018-4d22bbb62b3c h1:/h0vtH0PyU0xAoZJVcRw1k0Ng+U0JAy3QDiFmppIlIE=
|
||||
golang.org/x/sys v0.0.0-20200929083018-4d22bbb62b3c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201113233024-12cec1faf1ba h1:xmhUJGQGbxlod18iJGqVEp9cHIPLl7QiX2aA3to708s=
|
||||
golang.org/x/sys v0.0.0-20201113233024-12cec1faf1ba/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210331175145-43e1dd70ce54 h1:rF3Ohx8DRyl8h2zw9qojyLHLhrJpEMgyPOImREEryf0=
|
||||
golang.org/x/sys v0.0.0-20210331175145-43e1dd70ce54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59 h1:QjA/9ArTfVTLfEhClDCG7SGrZkZixxWpwNCDiwJfh88=
|
||||
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200923182640-463111b69878 h1:VUw1+Jf6KJPf82mbTQMia6HCnNMv2BbAipkEZ4KTcqQ=
|
||||
golang.org/x/tools v0.0.0-20200923182640-463111b69878/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||
golang.org/x/tools v0.0.0-20200924182824-0f1c53950d78 h1:3JUoxVhcskhsIDEc7vg0MUUEpmPPN5TfG+E97z/Fn90=
|
||||
golang.org/x/tools v0.0.0-20200924182824-0f1c53950d78/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||
golang.org/x/tools v0.0.0-20200929191002-f1e51e6b9437 h1:XSFqH8m531iIGazX5lrUC9j3slbwsZ1GFByqdUrLqmI=
|
||||
golang.org/x/tools v0.0.0-20200929191002-f1e51e6b9437/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||
golang.org/x/tools v0.0.0-20201008184944-d01b322e6f06 h1:w9ail9jFLaySAm61Zjhciu0LQ5i8YTy2pimlNLx4uuk=
|
||||
golang.org/x/tools v0.0.0-20201008184944-d01b322e6f06/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||
golang.org/x/tools v0.0.0-20201017001424-6003fad69a88 h1:ZB1XYzdDo7c/O48jzjMkvIjnC120Z9/CwgDWhePjQdQ=
|
||||
golang.org/x/tools v0.0.0-20201017001424-6003fad69a88/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||
golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9 h1:sEvmEcJVKBNUvgCUClbUQeHOAa9U0I2Ce1BooMvVCY4=
|
||||
golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201103235415-b653051172e4 h1:Qe0EMgvVYb6tmJhJHljCj3gS96hvSTkGNaIzp/ivq10=
|
||||
golang.org/x/tools v0.0.0-20201103235415-b653051172e4/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201113202037-1643af1435f3 h1:7R7+wzd5VuLvCNyHZ/MG511kkoP/DBEzkbh8qUsFbY8=
|
||||
golang.org/x/tools v0.0.0-20201113202037-1643af1435f3/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201114224030-61ea331ec02b h1:Ych5r0Z6MLML1fgf5hTg9p5bV56Xqx9xv9hLgMBATWs=
|
||||
golang.org/x/tools v0.0.0-20201114224030-61ea331ec02b/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201120155355-20be4ac4bd6e h1:t96dS3DO8DGjawSLJL/HIdz8CycAd2v07XxqB3UPTi0=
|
||||
golang.org/x/tools v0.0.0-20201120155355-20be4ac4bd6e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210104081019-d8d6ddbec6ee h1:5xKxdl/RhlelmSPaxyVeq5PYSmJ4H14yeQT58qP1F6o=
|
||||
golang.org/x/tools v0.0.0-20210104081019-d8d6ddbec6ee/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
@@ -416,36 +338,32 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
|
||||
gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc=
|
||||
gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
||||
gopkg.in/ini.v1 v1.57.0 h1:9unxIsFcTt4I55uWluz+UmL95q4kdJ0buvQ1ZIqVQww=
|
||||
gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.60.0 h1:P5ZzC7RJO04094NJYlEnBdFK2wwmnCAy/+7sAzvWs60=
|
||||
gopkg.in/ini.v1 v1.60.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.61.0 h1:LBCdW4FmFYL4s/vDZD1RQYX7oAR6IjujCYgMdbHBR10=
|
||||
gopkg.in/ini.v1 v1.61.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
|
||||
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc h1:/hemPrYIhOhy8zYrNj+069zDB68us2sMGsfkFJO0iZs=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="{{ .cssClass }}">
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="css/base.css">
|
||||
<link rel="stylesheet" type="text/css" href="css/bundle.css">
|
||||
{{ template "header.html" . }}
|
||||
<title>404 - jfa-go</title>
|
||||
</head>
|
||||
|
||||
487
html/admin.html
@@ -1,14 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="{{ .cssClass }}">
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="css/base.css">
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="{{ .urlBase }}/css/bundle.css">
|
||||
<script>
|
||||
window.URLBase = "{{ .urlBase }}";
|
||||
window.notificationsEnabled = {{ .notifications }};
|
||||
window.emailEnabled = {{ .email_enabled }};
|
||||
window.telegramEnabled = {{ .telegram_enabled }};
|
||||
window.ombiEnabled = {{ .ombiEnabled }};
|
||||
window.usernamesEnabled = {{ .username }};
|
||||
window.usernameEnabled = {{ .username }};
|
||||
window.langFile = JSON.parse({{ .language }});
|
||||
window.language = "{{ .langName }}";
|
||||
</script>
|
||||
{{ template "header.html" . }}
|
||||
<title>Admin - jfa-go</title>
|
||||
@@ -16,229 +18,475 @@
|
||||
<body class="max-w-full overflow-x-hidden section">
|
||||
<div id="modal-login" class="modal">
|
||||
<form class="modal-content card" id="form-login" href="">
|
||||
<span class="heading">Login</span>
|
||||
<input type="text" class="field input ~neutral !high mt-half mb-1" placeholder="username" id="login-user">
|
||||
<input type="password" class="field input ~neutral !high mb-1" placeholder="password" id="login-password">
|
||||
<span class="heading">{{ .strings.login }}</span>
|
||||
<input type="text" class="field input ~neutral !high mt-half mb-1" placeholder="{{ .strings.username }}" id="login-user">
|
||||
<input type="password" class="field input ~neutral !high mb-1" placeholder="{{ .strings.password }}" id="login-password">
|
||||
<label>
|
||||
<input type="submit" class="unfocused">
|
||||
<span class="button ~urge !normal full-width center supra submit">Login</span>
|
||||
<span class="button ~urge !normal full-width center supra submit">{{ .strings.login }}</span>
|
||||
</label>
|
||||
</form>
|
||||
</div>
|
||||
<div id="modal-add-user" class="modal">
|
||||
<form class="modal-content card" id="form-add-user" href="">
|
||||
<span class="heading">New User <span class="modal-close">×</span></span>
|
||||
<input type="text" class="field input ~neutral !high mt-half mb-1" placeholder="username" id="add-user-user">
|
||||
<input type="email" class="field input ~neutral !high mt-half mb-1" placeholder="email address">
|
||||
<input type="password" class="field input ~neutral !high mb-1" placeholder="password" id="add-user-password">
|
||||
<span class="heading">{{ .strings.newUser }} <span class="modal-close">×</span></span>
|
||||
<input type="text" class="field input ~neutral !high mt-half mb-1" placeholder="{{ .strings.username }}" id="add-user-user">
|
||||
<input type="email" class="field input ~neutral !high mt-half mb-1" placeholder="{{ .strings.emailAddress }}">
|
||||
<input type="password" class="field input ~neutral !high mb-1" placeholder="{{ .strings.password }}" id="add-user-password">
|
||||
<label>
|
||||
<input type="submit" class="unfocused">
|
||||
<span class="button ~urge !normal full-width center supra submit">Create</span>
|
||||
<span class="button ~urge !normal full-width center supra submit">{{ .strings.create }}</span>
|
||||
</label>
|
||||
</form>
|
||||
</div>
|
||||
<div id="modal-about" class="modal">
|
||||
<div class="modal-content content card">
|
||||
<span class="heading">About <span class="modal-close">×</span></span>
|
||||
<img src="/banner.svg" class="mt-1" alt="jfa-go banner">
|
||||
<img src="{{ .urlBase }}/banner.svg" class="banner header" alt="jfa-go banner">
|
||||
<span class="heading"><span class="modal-close">×</span></span>
|
||||
<p><i class="icon ri-github-fill"></i><a href="https://github.com/hrfee/jfa-go">jfa-go</a></p>
|
||||
<p>Version <span class="code monospace">{{ .version }}</span></p>
|
||||
<p>Commit <span class="code monospace">{{ .commit }}</span></p>
|
||||
<p>{{ .strings.version }} <span class="code monospace">{{ .version }}</span></p>
|
||||
<p>{{ .strings.commitNoun }} <span class="code monospace">{{ .commit }}</span></p>
|
||||
<div class="dropdown" tabindex="0">
|
||||
<span class="button ~info dropdown-button">
|
||||
<i class="ri-hand-heart-line mr-half"></i>
|
||||
{{ .strings.donate }}
|
||||
<span class="ml-1 chev"></span>
|
||||
</span>
|
||||
<div class="dropdown-display">
|
||||
<div class="card ~neutral !low">
|
||||
<a href="https://github.com/sponsors/hrfee" target="_blank" class="button input ~neutral field mb-half lang-link">GitHub</a>
|
||||
<a href="https://ko-fi.com/hrfee" target="_blank" class="button input ~neutral field mb-half lang-link">Ko-fi</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p><a href="https://github.com/hrfee/jfa-go/blob/main/LICENSE">Available under the MIT License.</a></p>
|
||||
<pre class="monospace">{{ .license }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div id="modal-modify-user" class="modal">
|
||||
<form class="modal-content card" id="form-modify-user" href="">
|
||||
<span class="heading">Modify Settings for <span id="header-modify-user"></span> <span class="modal-close">×</span></span>
|
||||
<p class="content">Apply settings from an existing profile, or source them directly from a user.</p>
|
||||
<span class="heading"><span id="header-modify-user"></span> <span class="modal-close">×</span></span>
|
||||
<p class="content">{{ .strings.modifySettingsDescription }}</p>
|
||||
<div class="flex-row mb-1">
|
||||
<label class="flex-row-group mr-1">
|
||||
<input type="radio" name="modify-user-source" class="unfocused" id="radio-use-profile" checked>
|
||||
<span class="button ~neutral !high supra full-width center">Profile</span>
|
||||
<span class="button ~neutral !high supra full-width center">{{ .strings.profile }}</span>
|
||||
</label>
|
||||
<label class="flex-row-group ml-1">
|
||||
<input type="radio" name="modify-user-source" class="unfocused" id="radio-use-user">
|
||||
<span class="button ~neutral !normal supra full-width center">User</span>
|
||||
<span class="button ~neutral !normal supra full-width center">{{ .strings.user }}</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="select ~neutral !normal mb-1">
|
||||
<select id="modify-user-profiles">
|
||||
<option>Friends</option>
|
||||
<option>Family</option>
|
||||
<option>Default</option>
|
||||
</select>
|
||||
<select id="modify-user-profiles"></select>
|
||||
</div>
|
||||
<div class="select ~neutral !normal mb-1 unfocused">
|
||||
<select id="modify-user-users">
|
||||
<option>Person</option>
|
||||
<option>Other person</option>
|
||||
</select>
|
||||
<select id="modify-user-users"></select>
|
||||
</div>
|
||||
<label class="switch mb-1">
|
||||
<input type="checkbox" id="modify-user-homescreen" checked>
|
||||
<span>Apply homescreen layout</span>
|
||||
<span>{{ .strings.applyHomescreenLayout }}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="submit" class="unfocused">
|
||||
<span class="button ~urge !normal full-width center supra submit">Apply</span>
|
||||
<span class="button ~urge !normal full-width center supra submit">{{ .strings.apply }}</span>
|
||||
</label>
|
||||
</form>
|
||||
</div>
|
||||
<div id="modal-delete-user" class="modal">
|
||||
<form class="modal-content card" id="form-delete-user" href="">
|
||||
<span class="heading">Delete <span id="header-delete-user"></span> <span class="modal-close">×</span></span>
|
||||
<span class="heading"><span id="header-delete-user"></span> <span class="modal-close">×</span></span>
|
||||
<div class="content mt-half">
|
||||
<label class="switch mb-1">
|
||||
<input type="checkbox" id="delete-user-notify" checked>
|
||||
<span>Send notification email</span>
|
||||
<span>{{ .strings.sendDeleteNotificationEmail }}</span>
|
||||
</label>
|
||||
<textarea id="textarea-delete-user" class="textarea full-width ~neutral !normal mb-1" placeholder="Your account has been deleted."></textarea>
|
||||
<textarea id="textarea-delete-user" class="textarea full-width ~neutral !normal mb-1" placeholder="{{ .strings.sendDeleteNotificationExample }}"></textarea>
|
||||
<label>
|
||||
<input type="submit" class="unfocused">
|
||||
<span class="button ~critical !normal full-width center supra submit">Delete</span>
|
||||
<span class="button ~critical !normal full-width center supra submit">{{ .strings.delete }}</span>
|
||||
</label>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div id="modal-extend-expiry" class="modal">
|
||||
<form class="modal-content card" id="form-extend-expiry" href="">
|
||||
<span class="heading"><span id="header-extend-expiry"></span> <span class="modal-close">×</span></span>
|
||||
<div class="content mt-half">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<label class="label supra" for="extend-expiry-months">{{ .strings.inviteMonths }}</label>
|
||||
<div class="select ~neutral !normal mb-1 mt-half">
|
||||
<select id="extend-expiry-months">
|
||||
<option>0</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label class="label supra" for="extend-expiry-days">{{ .strings.inviteDays }}</label>
|
||||
<div class="select ~neutral !normal mb-1 mt-half">
|
||||
<select id="extend-expiry-days">
|
||||
<option>0</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<label class="label supra" for="extend-expiry-hours">{{ .strings.inviteHours }}</label>
|
||||
<div class="select ~neutral !normal mb-1 mt-half">
|
||||
<select id="extend-expiry-hours">
|
||||
<option>0</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label class="label supra" for="extend-expiry-minutes">{{ .strings.inviteMinutes }}</label>
|
||||
<div class="select ~neutral !normal mb-1 mt-half">
|
||||
<select id="extend-expiry-minutes">
|
||||
<option>0</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<label>
|
||||
<input type="submit" class="unfocused">
|
||||
<span class="button ~critical !normal full-width center supra submit">{{ .strings.submit }}</span>
|
||||
</label>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div id="modal-announce" class="modal">
|
||||
<form class="modal-content wide card" id="form-announce" href="">
|
||||
<span class="heading"><span id="header-announce"></span> <span class="modal-close">×</span></span>
|
||||
<div class="row">
|
||||
<div class="col flex-col content mt-half">
|
||||
<label class="label supra" for="announce-subject"> {{ .strings.subject }}</label>
|
||||
<input type="text" id="announce-subject" class="input ~neutral !normal mb-1 mt-half">
|
||||
<label class="label supra" for="textarea-announce">{{ .strings.message }}</label>
|
||||
<textarea id="textarea-announce" class="textarea full-width ~neutral !normal mt-half monospace"></textarea>
|
||||
<p class="support mt-half mb-1">{{ .strings.markdownSupported }}</p>
|
||||
<label>
|
||||
<input type="submit" class="unfocused">
|
||||
<span class="button ~urge !normal full-width center supra submit">{{ .strings.submit }}</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="col card ~neutral !low">
|
||||
<span class="subheading supra">{{ .strings.preview }}</span>
|
||||
<div class="mt-half" id="announce-preview"></div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div id="modal-customize" class="modal">
|
||||
<div class="modal-content card">
|
||||
<span class="heading">{{ .strings.customizeMessages }} <span class="modal-close">×</span></span>
|
||||
<p class="content">{{ .strings.customizeMessagesDescription }}</p>
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ .strings.name }}</th>
|
||||
<th>{{ .strings.reset }}</th>
|
||||
<th>{{ .strings.edit }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="customize-list"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="modal-editor" class="modal">
|
||||
<form class="modal-content wide card" id="form-editor" href="">
|
||||
<span class="heading"><span id="header-editor"></span> <span class="modal-close">×</span></span>
|
||||
<div class="row">
|
||||
<div class="col flex-col content mt-half">
|
||||
<span class="label supra" for="editor-variables" id="label-editor-variables">{{ .strings.variables }}</span>
|
||||
<div id="editor-variables"></div>
|
||||
<span class="label supra" for="editor-conditionals" id="label-editor-conditionals">{{ .strings.conditionals }}</span>
|
||||
<div id="editor-conditionals"></div>
|
||||
<label class="label supra" for="textarea-editor">{{ .strings.message }}</label>
|
||||
<textarea id="textarea-editor" class="textarea full-width flex-auto ~neutral !normal mt-half monospace"></textarea>
|
||||
<p class="support mt-half mb-1">{{ .strings.markdownSupported }}</p>
|
||||
<div class="flex-row">
|
||||
<label class="full-width ml-half">
|
||||
<input type="submit" class="unfocused">
|
||||
<span class="button ~urge !normal full-width center supra submit">{{ .strings.submit }}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col card ~neutral !low">
|
||||
<span class="subheading supra">{{ .strings.preview }}</span>
|
||||
<div class="mt-half" id="editor-preview"></div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div id="modal-restart" class="modal">
|
||||
<div class="modal-content card ~critical !low">
|
||||
<span class="heading">Restart needed <span class="modal-close">×</span></span>
|
||||
<p class="content pb-1">A restart is needed to apply some settings you changed. Do it now or later?</p>
|
||||
<span class="heading">{{ .strings.settingsRestartRequired }} <span class="modal-close">×</span></span>
|
||||
<p class="content pb-1">{{ .strings.settingsRestartRequiredDescription }}</p>
|
||||
<div class="fr">
|
||||
<span class="button ~info !normal" id="settings-apply-no-restart">Apply, restart later</span>
|
||||
<span class="button ~critical !normal" id="settings-apply-restart">Apply & restart</span>
|
||||
<span class="button ~info !normal mb-half" id="settings-apply-no-restart">{{ .strings.settingsApplyRestartLater }}</span>
|
||||
<span class="button ~critical !normal" id="settings-apply-restart">{{ .strings.settingsApplyRestartNow }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="modal-refresh" class="modal">
|
||||
<div class="modal-content card ~neutral !normal">
|
||||
<span class="heading">Settings applied.</span>
|
||||
<p class="content">Refresh the page in a few seconds.</p>
|
||||
<span class="heading">{{ .strings.settingsApplied }}</span>
|
||||
<p class="content">{{ .strings.settingsRefreshPage }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="modal-ombi-defaults" class="modal">
|
||||
<form class="modal-content card" id="form-ombi-defaults" href="">
|
||||
<span class="heading">Ombi user defaults <span class="modal-close">×</span></span>
|
||||
<p class="content">Create an Ombi user and configure it, then select it here. It's settings/permissions will be stored and applied to new ombi users created by jfa-go.</p>
|
||||
<span class="heading">{{ .strings.ombiUserDefaults }} <span class="modal-close">×</span></span>
|
||||
<p class="content">{{ .strings.ombiUserDefaultsDescription }}</p>
|
||||
<div class="select ~neutral !normal mb-1">
|
||||
<select>
|
||||
<option>Person</option>
|
||||
<option>Other person</option>
|
||||
</select>
|
||||
<select></select>
|
||||
</div>
|
||||
<label>
|
||||
<input type="submit" class="unfocused">
|
||||
<span class="button ~urge !normal full-width center supra submit">Submit</span>
|
||||
<span class="button ~urge !normal full-width center supra submit">{{ .strings.submit }}</span>
|
||||
</label>
|
||||
</form>
|
||||
</div>
|
||||
<div id="modal-user-profiles" class="modal">
|
||||
<div class="modal-content wide card">
|
||||
<span class="heading">User profiles <span class="modal-close">×</span></span>
|
||||
<p class="support lg">Profiles are applied to users when they create an account. A profile includes library access rights and homescreen layout.</p>
|
||||
<span class="heading">{{ .strings.userProfiles }} <span class="modal-close">×</span></span>
|
||||
<p class="support lg">{{ .strings.userProfilesDescription }}</p>
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Default</th>
|
||||
<th>From</th>
|
||||
<th>Libraries</th>
|
||||
<th><span class="button ~neutral !high" id="button-profile-create">Create</span></th>
|
||||
<th>{{ .strings.name }}</th>
|
||||
<th>{{ .strings.userProfilesIsDefault }}</th>
|
||||
<th>{{ .strings.from }}</th>
|
||||
<th>{{ .strings.userProfilesLibraries }}</th>
|
||||
<th><span class="button ~neutral !high" id="button-profile-create">{{ .strings.create }}</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="table-profiles">
|
||||
</tbody>
|
||||
<tbody id="table-profiles"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="modal-add-profile" class="modal">
|
||||
<form class="modal-content card" id="form-add-profile" href="">
|
||||
<span class="heading">Add profile <span class="modal-close">×</span></span>
|
||||
<p class="content">Create a Jellyfin user and configure it. Select it here, and when this profile is applied to an invite, new users will be created with its settings.</p>
|
||||
<span class="heading">{{ .strings.addProfile }} <span class="modal-close">×</span></span>
|
||||
<p class="content">{{ .strings.addProfileDescription }}</p>
|
||||
<label>
|
||||
<span class="supra">Profile Name </span>
|
||||
<input type="text" class="field input ~neutral !high mt-half mb-1" placeholder="Name" id="add-profile-name">
|
||||
<span class="supra">{{ .strings.addProfileNameOf }} </span>
|
||||
<input type="text" class="field input ~neutral !high mt-half mb-1" placeholder="{{ .strings.name }}" id="add-profile-name">
|
||||
<label>
|
||||
<span class="supra">User</span>
|
||||
<span class="supra">{{ .strings.user }}</span>
|
||||
<div class="select ~neutral !normal mt-half mb-1">
|
||||
<select id="add-profile-user">
|
||||
</select>
|
||||
<select id="add-profile-user"></select>
|
||||
</div>
|
||||
</label>
|
||||
<label class="switch mb-1">
|
||||
<input type="checkbox" id="add-profile-homescreen" checked>
|
||||
<span>Store homescreen layout</span>
|
||||
<span>{{ .strings.addProfileStoreHomescreenLayout }}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="submit" class="unfocused">
|
||||
<span class="button ~urge !normal full-width center supra submit">Create</span>
|
||||
<span class="button ~urge !normal full-width center supra submit">{{ .strings.create }}</span>
|
||||
</label>
|
||||
</form>
|
||||
</div>
|
||||
<div id="modal-update" class="modal">
|
||||
<div class="modal-content wide card">
|
||||
<span class="heading">{{ .strings.updates }} <span class="modal-close">×</span></span>
|
||||
<p class="content">
|
||||
<h2>
|
||||
<a id="update-version"></a> (<span class="monospace" id="update-commit"></span>)
|
||||
</h2>
|
||||
<p class="content" id="update-description"></p>
|
||||
<p class="support" id="update-date"></p>
|
||||
<div class="content markdown-box" id="update-changelog"></div>
|
||||
</p>
|
||||
<span class="button ~info !normal full-width center" id="update-download">{{ .strings.download }}</span>
|
||||
<span class="button ~urge !normal full-width center" id="update-update">{{ .strings.update }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{{ if .telegram_enabled }}
|
||||
<div id="modal-telegram" class="modal">
|
||||
<div class="modal-content card">
|
||||
<span class="heading mb-1">{{ .strings.linkTelegram }}</span>
|
||||
<p class="content mb-1">{{ .strings.sendPIN }}</p>
|
||||
<h1 class="ac" id="telegram-pin"></h1>
|
||||
<a class="subheading link-center" id="telegram-link" target="_blank">
|
||||
<span class="shield ~info mr-1">
|
||||
<span class="icon">
|
||||
<i class="ri-telegram-line"></i>
|
||||
</span>
|
||||
</span>
|
||||
@<span id="telegram-username">
|
||||
</a>
|
||||
<span class="button ~info !normal full-width center mt-1" id="telegram-waiting">{{ .strings.success }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
<div id="notification-box"></div>
|
||||
<span class="dropdown" tabindex="0" id="lang-dropdown">
|
||||
<span class="button ~urge dropdown-button">
|
||||
<i class="ri-global-line"></i>
|
||||
<span class="ml-1 chev"></span>
|
||||
</span>
|
||||
<div class="dropdown-display">
|
||||
<div class="card ~neutral !low">
|
||||
<label class="switch pb-1">
|
||||
<input type="radio" name="lang-time" id="lang-12h">
|
||||
<span>{{ .strings.time12h }}</span>
|
||||
</label>
|
||||
<label class="switch pb-1">
|
||||
<input type="radio" name="lang-time" id="lang-24h">
|
||||
<span>{{ .strings.time24h }}</span>
|
||||
</label>
|
||||
<div id="lang-list"></div>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
<div class="page-container">
|
||||
<div class="mb-1">
|
||||
<header class="flex flex-wrap items-center justify-between">
|
||||
<div class="text-neutral-700">
|
||||
<span id="button-tab-invites" class="tab-button portal">Invites</span>
|
||||
<span id="button-tab-accounts" class="tab-button portal">Accounts</span>
|
||||
<span id="button-tab-settings" class="tab-button portal">Settings</span>
|
||||
<span id="button-tab-invites" class="tab-button portal">{{ .strings.invites }}</span>
|
||||
<span id="button-tab-accounts" class="tab-button portal">{{ .strings.accounts }}</span>
|
||||
<span id="button-tab-settings" class="tab-button portal">{{ .strings.settings }}</span>
|
||||
</div>
|
||||
</header>
|
||||
</div>
|
||||
<div class="mb-1">
|
||||
<div class="text-neutral-700">
|
||||
<span class="button ~critical !normal mb-1 unfocused" id="logout-button">Logout</span>
|
||||
<span id="button-theme" class="button ~neutral !normal mb-1">Theme</span>
|
||||
<span class="button ~critical !normal mb-1 unfocused" id="logout-button">{{ .strings.logout }}</span>
|
||||
<span id="button-theme" class="button ~neutral !normal mb-1">{{ .strings.theme }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="tab-invites">
|
||||
<div class="card ~neutral !low invites mb-1">
|
||||
<span class="heading">Invites</span>
|
||||
<span class="heading">{{ .strings.invites }}</span>
|
||||
<div id="invites"></div>
|
||||
</div>
|
||||
<div class="card ~neutral !low">
|
||||
<span class="heading">Create</span>
|
||||
<span class="heading">{{ .strings.create }}</span>
|
||||
<div class="row" id="create-inv">
|
||||
<div class="card ~neutral !normal col">
|
||||
<label class="label supra" for="create-days">Days</label>
|
||||
<div class="select ~neutral !normal mb-1 mt-half">
|
||||
<select id="create-days">
|
||||
<option>0</option>
|
||||
</select>
|
||||
<div class="row mb-1">
|
||||
<label class="col mr-1">
|
||||
<input type="radio" name="duration" class="unfocused" id="radio-inv-duration" checked>
|
||||
<span class="button ~neutral !high supra full-width center">{{ .strings.inviteDuration }}</span>
|
||||
</label>
|
||||
<label class="col ml-1">
|
||||
<input type="radio" name="duration" class="unfocused" id="radio-user-expiry">
|
||||
<span class="button ~neutral !normal supra full-width center">{{ .strings.userExpiry }}</span>
|
||||
</label>
|
||||
</div>
|
||||
<label class="label supra" for="create-hours">Hours</label>
|
||||
<div class="select ~neutral !normal mb-1 mt-half">
|
||||
<select id="create-hours">
|
||||
<option>0</option>
|
||||
</select>
|
||||
<div id="inv-duration">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<label class="label supra" for="create-months">{{ .strings.inviteMonths }}</label>
|
||||
<div class="select ~neutral !normal mb-1 mt-half">
|
||||
<select id="create-months">
|
||||
<option>0</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label class="label supra" for="create-days">{{ .strings.inviteDays }}</label>
|
||||
<div class="select ~neutral !normal mb-1 mt-half">
|
||||
<select id="create-days">
|
||||
<option>0</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<label class="label supra" for="create-hours">{{ .strings.inviteHours }}</label>
|
||||
<div class="select ~neutral !normal mb-1 mt-half">
|
||||
<select id="create-hours">
|
||||
<option>0</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label class="label supra" for="create-minutes">{{ .strings.inviteMinutes }}</label>
|
||||
<div class="select ~neutral !normal mb-1 mt-half">
|
||||
<select id="create-minutes">
|
||||
<option>0</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<label class="label supra" for="create-minutes">Minutes</label>
|
||||
<div class="select ~neutral !normal mb-1 mt-half">
|
||||
<select id="create-minutes">
|
||||
<option>0</option>
|
||||
</select>
|
||||
<div id="user-expiry" class="unfocused">
|
||||
<p class="support">{{ .strings.userExpiryDescription }}</p>
|
||||
<div class="mb-half">
|
||||
<label for="create-user-expiry-enabled" class="button ~neutral !normal">
|
||||
<input type="checkbox" id="create-user-expiry-enabled" aria-label="User duration enabled">
|
||||
<span class="ml-half">{{ .strings.enabled }} </span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<label class="label supra" for="user-months">{{ .strings.inviteMonths }}</label>
|
||||
<div class="select ~neutral !normal mb-1 mt-half">
|
||||
<select id="user-months">
|
||||
<option>0</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label class="label supra" for="user-days">{{ .strings.inviteDays }}</label>
|
||||
<div class="select ~neutral !normal mb-1 mt-half">
|
||||
<select id="user-days">
|
||||
<option>0</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<label class="label supra" for="user-hours">{{ .strings.inviteHours }}</label>
|
||||
<div class="select ~neutral !normal mb-1 mt-half">
|
||||
<select id="user-hours">
|
||||
<option>0</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label class="label supra" for="user-minutes">{{ .strings.inviteMinutes }}</label>
|
||||
<div class="select ~neutral !normal mb-1 mt-half">
|
||||
<select id="user-minutes">
|
||||
<option>0</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label class="label supra" for="create-label"> {{ .strings.label }}</label>
|
||||
<input type="text" id="create-label" class="input ~neutral !normal mb-1 mt-half">
|
||||
</div>
|
||||
</div>
|
||||
<div class="card ~neutral !normal col">
|
||||
<label class="label supra" for="create-uses">Number of uses</label>
|
||||
<label class="label supra" for="create-uses">{{ .strings.inviteNumberOfUses }}</label>
|
||||
<div class="flex-expand mb-1 mt-half">
|
||||
<input type="number" min="0" id="create-uses" class="input ~neutral !normal mr-1" value=1>
|
||||
<label for="create-inf-uses" class="button ~neutral !normal">
|
||||
<label for="create-inf-uses" class="button ~neutral !normal" title="Set uses to infinite">
|
||||
<span>∞</span>
|
||||
<input type="checkbox" class="unfocused" id="create-inf-uses" aria-label="Set uses to infinite">
|
||||
</label>
|
||||
</div>
|
||||
<p class="support unfocused" id="create-inf-uses-warning"><span class="badge ~critical">Warning</span> invites with infinite uses can be used abusively.</p>
|
||||
<label class="label supra">Profile</label>
|
||||
<p class="support unfocused" id="create-inf-uses-warning"><span class="badge ~critical">{{ .strings.warning }}</span> {{ .strings.inviteInfiniteUsesWarning }}</p>
|
||||
<label class="label supra">{{ .strings.profile }}</label>
|
||||
<div class="select ~neutral !normal mb-1 mt-half">
|
||||
<select id="create-profile">
|
||||
</select>
|
||||
</div>
|
||||
<div id="create-send-to-container">
|
||||
<label class="label supra">Send to</label>
|
||||
<label class="label supra">{{ .strings.inviteSendToEmail }}</label>
|
||||
<div class="flex-expand mb-1 mt-half">
|
||||
<input type="email" id="create-send-to" class="input ~neutral !normal mr-1" placeholder="example@example.com">
|
||||
<label for="create-send-to-enabled" class="button ~neutral !normal">
|
||||
@@ -246,27 +494,39 @@
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<span class="button ~urge !normal supra full-width center lg" id="create-submit">Create</span>
|
||||
<span class="button ~urge !normal supra full-width center lg" id="create-submit">{{ .strings.create }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="tab-accounts" class="unfocused">
|
||||
<div class="card ~neutral !low accounts mb-1">
|
||||
<span class="heading">Accounts</span>
|
||||
<div class="fr">
|
||||
<span class="button ~neutral !normal" id="accounts-add-user">Add User</span>
|
||||
<span class="button ~urge !normal" id="accounts-modify-user">Modify Settings</span>
|
||||
<span class="button ~critical !normal" id="accounts-delete-user">Delete User</span>
|
||||
<div class="flex-expand row">
|
||||
<div class="row">
|
||||
<span class="heading mr-1 col sm">{{ .strings.accounts }}</span>
|
||||
<input type="search" class="col sm field ~neutral !normal input search ml-1 mr-1" id="accounts-search" placeholder="{{ .strings.search }}">
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="col sm button ~neutral !normal center mb-half" id="accounts-add-user">{{ .quantityStrings.addUser.Singular }}</span>
|
||||
<span class="col sm button ~info !normal center mb-half" id="accounts-announce">{{ .strings.announce }}</span>
|
||||
<span class="col sm button ~urge !normal center mb-half" id="accounts-modify-user">{{ .strings.modifySettings }}</span>
|
||||
<span class="col sm button ~warning !normal center mb-half" id="accounts-extend-expiry">{{ .strings.extendExpiry }}</span>
|
||||
<span class="col sm button ~positive !normal center mb-half" id="accounts-disable-enable">{{ .strings.disable }}</span>
|
||||
<span class="col sm button ~critical !normal center mb-half" id="accounts-delete-user">{{ .quantityStrings.deleteUser.Singular }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card ~neutral !normal accounts-header table-responsive mt-half">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><input type="checkbox" value="" id="accounts-select-all"></th>
|
||||
<th>Username</th>
|
||||
<th>Email Address</th>
|
||||
<th>Last Active</th>
|
||||
<th>{{ .strings.username }}</th>
|
||||
<th>{{ .strings.emailAddress }}</th>
|
||||
{{ if .telegram_enabled }}
|
||||
<th>Telegram</th>
|
||||
{{ end }}
|
||||
<th>{{ .strings.expiry }}</th>
|
||||
<th>{{ .strings.lastActiveTime }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="accounts-list"></tbody>
|
||||
@@ -276,21 +536,30 @@
|
||||
</div>
|
||||
<div id="tab-settings" class="unfocused">
|
||||
<div class="card ~neutral !low settings overflow">
|
||||
<span class="heading">Settings</span>
|
||||
<div class="fr">
|
||||
<span class="button ~neutral !normal unfocused" id="settings-save">Save</span>
|
||||
<div class="flex-expand">
|
||||
<div class="flex-row">
|
||||
<span class="heading">{{ .strings.settings }}</span>
|
||||
<label for="settings-advanced-enabled" class="button ~neutral !normal ml-1">
|
||||
<input type="checkbox" id="settings-advanced-enabled" aria-label="Advanced settings enabled">
|
||||
<span class="ml-half">{{ .strings.advancedSettings }} </span>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<span class="button ~neutral !normal" id="settings-restart">{{ .strings.settingsRestart }}</span>
|
||||
<span class="button ~urge !normal unfocused" id="settings-save">{{ .strings.settingsSave }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="card ~neutral !normal col" id="settings-sidebar">
|
||||
<aside class="aside sm ~info mb-half">Note: <span class="badge ~critical">*</span> indicates a required field, <span class="badge ~info">R</span> indicates changes require a restart.</aside>
|
||||
<span class="button ~neutral !low settings-section-button mb-half" id="setting-about"><span class="flex">About <i class="ri-information-line ml-half"></i></span></span>
|
||||
<span class="button ~neutral !low settings-section-button mb-half" id="setting-profiles"><span class="flex">User profiles <i class="ri-user-line ml-half"></i></span></span>
|
||||
<aside class="aside sm ~info mb-half" id="settings-message">Note: <span class="badge ~critical">*</span> indicates a required field, <span class="badge ~info">R</span> indicates changes require a restart.</aside>
|
||||
<span class="button ~neutral !low settings-section-button mb-half" id="setting-about"><span class="flex">{{ .strings.aboutProgram }} <i class="ri-information-line ml-half"></i></span></span>
|
||||
<span class="button ~neutral !low settings-section-button mb-half" id="setting-profiles"><span class="flex">{{ .strings.userProfiles }} <i class="ri-user-line ml-half"></i></span></span>
|
||||
</div>
|
||||
<div class="card ~neutral !normal col overflow" id="settings-panel"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="js/admin.js" type="module"></script>
|
||||
<script src="{{ .urlBase }}/js/admin.js" type="module"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
18
html/create-success.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="{{ .cssClass }}">
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="css/bundle.css">
|
||||
{{ template "header.html" . }}
|
||||
<title>{{ .strings.successHeader }} - jfa-go</title>
|
||||
</head>
|
||||
<body class="section">
|
||||
<div class="page-container">
|
||||
<div class="card ~neutral !normal mb-1">
|
||||
<span class="heading mb-1">{{ .strings.successHeader }}</span>
|
||||
<p class="content mb-1">{{ .successMessage }}</p>
|
||||
<a class="button ~urge !normal full-width center supra submit" href="{{ .jfLink }}" id="create-success-button">{{ .strings.successContinueButton }}</a>
|
||||
</div>
|
||||
<i class="content">{{ .contactMessage }}</i>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,9 +1,22 @@
|
||||
{{ define "form-base" }}
|
||||
<script>
|
||||
window.usernameEnabled = {{ .username }};
|
||||
window.validationStrings = JSON.parse({{ .lang.validationStrings }});
|
||||
window.invalidPassword = "{{ .lang.reEnterPasswordInvalid }}";
|
||||
window.validationStrings = JSON.parse({{ .validationStrings }});
|
||||
window.invalidPassword = "{{ .strings.reEnterPasswordInvalid }}";
|
||||
window.URLBase = "{{ .urlBase }}";
|
||||
window.code = "{{ .code }}";
|
||||
window.language = "{{ .langName }}";
|
||||
window.messages = JSON.parse({{ .notifications }});
|
||||
window.confirmation = {{ .confirmation }};
|
||||
window.userExpiryEnabled = {{ .userExpiry }};
|
||||
window.userExpiryMonths = {{ .userExpiryMonths }};
|
||||
window.userExpiryDays = {{ .userExpiryDays }};
|
||||
window.userExpiryHours = {{ .userExpiryHours }};
|
||||
window.userExpiryMinutes = {{ .userExpiryMinutes }};
|
||||
window.userExpiryMessage = {{ .userExpiryMessage }};
|
||||
window.telegramEnabled = {{ .telegramEnabled }};
|
||||
window.telegramRequired = {{ .telegramRequired }};
|
||||
window.telegramPIN = "{{ .telegramPIN }}";
|
||||
</script>
|
||||
<script src="js/form.js" type="module"></script>
|
||||
{{ end }}
|
||||
|
||||
@@ -1,50 +1,97 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="{{ .cssClass }}">
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="css/base.css">
|
||||
<link rel="stylesheet" type="text/css" href="css/bundle.css">
|
||||
{{ template "header.html" . }}
|
||||
<title>{{ .lang.pageTitle }}</title>
|
||||
<title>{{ .strings.pageTitle }}</title>
|
||||
</head>
|
||||
<body class="max-w-full overflow-x-hidden section">
|
||||
<div id="modal-success" class="modal">
|
||||
<div class="modal-content card">
|
||||
<span class="heading mb-1">{{ .lang.successHeader }}</span>
|
||||
<span class="heading mb-1">{{ .strings.successHeader }}</span>
|
||||
<p class="content mb-1">{{ .successMessage }}</p>
|
||||
<span class="button ~urge !normal full-width center supra submit" id="create-success-button">{{ .lang.successContinueButton }}</span>
|
||||
<a class="button ~urge !normal full-width center supra submit" href="{{ .jfLink }}" id="create-success-button">{{ .strings.successContinueButton }}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="modal-confirmation" class="modal">
|
||||
<div class="modal-content card">
|
||||
<span class="heading mb-1">{{ .strings.confirmationRequired }}</span>
|
||||
<p class="content mb-1">{{ .strings.confirmationRequiredMessage }}</p>
|
||||
</div>
|
||||
</div>
|
||||
{{ if .telegramEnabled }}
|
||||
<div id="modal-telegram" class="modal">
|
||||
<div class="modal-content card">
|
||||
<span class="heading mb-1">{{ .strings.linkTelegram }}</span>
|
||||
<p class="content mb-1">{{ .strings.sendPIN }}</p>
|
||||
<h1 class="ac">{{ .telegramPIN }}</h1>
|
||||
<a class="subheading link-center" href="{{ .telegramURL }}" target="_blank">
|
||||
<span class="shield ~info mr-1">
|
||||
<span class="icon">
|
||||
<i class="ri-telegram-line"></i>
|
||||
</span>
|
||||
</span>
|
||||
@{{ .telegramUsername }}
|
||||
</a>
|
||||
<span class="button ~info !normal full-width center mt-1" id="telegram-waiting">{{ .strings.success }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
<span class="dropdown" tabindex="0" id="lang-dropdown">
|
||||
<span class="button ~urge dropdown-button">
|
||||
<i class="ri-global-line"></i>
|
||||
<span class="ml-1 chev"></span>
|
||||
</span>
|
||||
<div class="dropdown-display">
|
||||
<div class="card ~neutral !low" id="lang-list">
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
<div id="notification-box"></div>
|
||||
<div class="page-container">
|
||||
<div class="card ~neutral !low">
|
||||
<div class="row baseline">
|
||||
<span class="col heading">{{ .lang.createAccountHeader }}</span>
|
||||
<span class="col heading">{{ .strings.createAccountHeader }}</span>
|
||||
<span class="col subheading"> {{ .helpMessage }}</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
{{ if .userExpiry }}
|
||||
<aside class="col aside sm ~warning" id="user-expiry-message"></aside>
|
||||
{{ end }}
|
||||
<form class="card ~neutral !normal" id="form-create" href="">
|
||||
<label class="label supra">
|
||||
{{ .lang.username }}
|
||||
<input type="text" class="input ~neutral !high mt-half mb-1" placeholder="{{ .lang.username }}" id="create-username" aria-label="{{ .lang.username }}">
|
||||
{{ .strings.username }}
|
||||
<input type="text" class="input ~neutral !high mt-half mb-1" placeholder="{{ .strings.username }}" id="create-username" aria-label="{{ .strings.username }}">
|
||||
</label>
|
||||
|
||||
<label class="label supra" for="create-email">{{ .lang.emailAddress }}</label>
|
||||
<input type="email" class="input ~neutral 1high mt-half mb-1" placeholder="{{ .lang.emailAddress }}" id="create-email" aria-label="{{ .lang.emailAddress }}" value="{{ .email }}">
|
||||
<label class="label supra" for="create-email">{{ .strings.emailAddress }}</label>
|
||||
<input type="email" class="input ~neutral !high mt-half mb-1" placeholder="{{ .strings.emailAddress }}" id="create-email" aria-label="{{ .strings.emailAddress }}" value="{{ .email }}">
|
||||
{{ if .telegramEnabled }}
|
||||
<span class="button ~info !normal full-width center mb-1" id="link-telegram">{{ .strings.linkTelegram }}</span>
|
||||
<div id="contact-via" class="unfocused">
|
||||
<label class="row switch pb-1">
|
||||
<input type="radio" name="contact-via" value="email"><span>Contact through Email</span>
|
||||
</label>
|
||||
<label class="row switch pb-1">
|
||||
<input type="radio" name="contact-via" value="telegram" id="contact-via-telegram"><span>Contact through Telegram</span>
|
||||
</label>
|
||||
</div>
|
||||
{{ end }}
|
||||
<label class="label supra" for="create-password">{{ .strings.password }}</label>
|
||||
<input type="password" class="input ~neutral !high mt-half mb-1" placeholder="{{ .strings.password }}" id="create-password" aria-label="{{ .strings.password }}">
|
||||
|
||||
<label class="label supra" for="create-password">{{ .lang.password }}</label>
|
||||
<input type="password" class="input ~neutral 1high mt-half mb-1" placeholder="{{ .lang.password }}" id="create-password" aria-label="{{ .lang.password }}">
|
||||
|
||||
<label class="label supra" for="create-reenter-password">{{ .lang.reEnterPassword }}</label>
|
||||
<input type="password" class="input ~neutral 1high mt-half mb-1" placeholder="{{ .lang.password }}" id="create-reenter-password" aria-label="{{ .lang.reEnterPassword }}">
|
||||
<label class="label supra" for="create-reenter-password">{{ .strings.reEnterPassword }}</label>
|
||||
<input type="password" class="input ~neutral !high mt-half mb-1" placeholder="{{ .strings.password }}" id="create-reenter-password" aria-label="{{ .strings.reEnterPassword }}">
|
||||
<label>
|
||||
<input type="submit" class="unfocused">
|
||||
<span class="button ~urge !normal full-width center supra submit">{{ .lang.createAccountButton }}</span>
|
||||
<span class="button ~urge !normal full-width center supra submit">{{ .strings.createAccountButton }}</span>
|
||||
</label>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card ~neutral !normal">
|
||||
<span class="label supra" for="inv-uses">{{ .lang.passwordRequirementsHeader }}</span>
|
||||
<span class="label supra" for="inv-uses">{{ .strings.passwordRequirementsHeader }}</span>
|
||||
<ul>
|
||||
{{ range $key, $value := .requirements }}
|
||||
<li class="" id="requirement-{{ $key }}" min="{{ $value }}">
|
||||
@@ -53,14 +100,13 @@
|
||||
{{ end }}
|
||||
</ul>
|
||||
</div>
|
||||
{{ if .contactMessage }}
|
||||
<aside class="col aside sm ~info">{{ .contactMessage }}</aside>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
window.validationStrings = {{ .lang.validationStrings }};
|
||||
</script>
|
||||
{{ template "form-base" . }}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="Description" content="jfa-go, a better way to manage Jellyfin users.">
|
||||
<meta name="color-scheme" content="dark light">
|
||||
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="{{ .urlBase }}/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="{{ .urlBase }}/favicon-32x32.png">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="{{ .cssClass }}">
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="css/base.css">
|
||||
<link rel="stylesheet" type="text/css" href="css/bundle.css">
|
||||
{{ template "header.html" . }}
|
||||
<title>Invalid Code - jfa-go</title>
|
||||
</head>
|
||||
|
||||
45
html/password-reset.html
Normal file
@@ -0,0 +1,45 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="{{ .cssClass }}">
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="css/bundle.css">
|
||||
{{ template "header.html" . }}
|
||||
<title>{{ .strings.passwordReset }} - jfa-go</title>
|
||||
</head>
|
||||
<body class="section">
|
||||
{{ if .success }}
|
||||
<div id="notification-box">
|
||||
<span id="copy-notification" class="unfocused">{{ .strings.copied }}</span>
|
||||
</div>
|
||||
{{ end }}
|
||||
<div class="page-container">
|
||||
<div class="card ~neutral !normal mb-1">
|
||||
<span class="heading mb-1">
|
||||
{{ if .success }}
|
||||
{{ .strings.passwordReset }}
|
||||
{{ else }}
|
||||
{{ .strings.resetFailed }}
|
||||
{{ end }}
|
||||
</span>
|
||||
<p class="content mb-1">
|
||||
{{ if .success }}
|
||||
{{ if .ombiEnabled }}
|
||||
{{ .strings.youCanLoginOmbi }}
|
||||
{{ else }}
|
||||
{{ .strings.youCanLogin }}
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
{{ .strings.tryAgain }}
|
||||
{{ end }}
|
||||
</p>
|
||||
{{ if .success }}
|
||||
<aside class="aside ~warning">
|
||||
{{ .strings.changeYourPassword }}
|
||||
</aside>
|
||||
<span class="button ~urge !normal full-width center supra p-1 mt-1" id="pin" title="{{ .strings.copy }}">{{ .pin }}</span>
|
||||
{{ end }}
|
||||
</div>
|
||||
<i class="content">{{ .contactMessage }}</i>
|
||||
</div>
|
||||
<script src="{{ .urlBase }}/js/pwr.js" type="module"></script>
|
||||
</body>
|
||||
</html>
|
||||
831
html/setup.html
@@ -1,374 +1,485 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html lang="en" class="light-theme">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-alpha3/dist/js/bootstrap.min.js" integrity="sha384-t6I8D5dJmMXjCsRLhSzCltuhNZg6P10kE0m0nAncLUjH6GeYLhRU1zfLoW3QNQDF" crossorigin="anonymous"></script>
|
||||
<style>
|
||||
.card-body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 10%;
|
||||
}
|
||||
.slider {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
overflow-x: hidden;
|
||||
-webkit-overflow-scrolling: none;
|
||||
scroll-snap-type: x mandatory;
|
||||
}
|
||||
.slider > div {
|
||||
scroll-snap-align: start;
|
||||
}
|
||||
.slide {
|
||||
width: 100%;
|
||||
flex-shrink: 0;
|
||||
height: 100%;
|
||||
margin: 10%;
|
||||
}
|
||||
</style>
|
||||
<title>Setup - jfa-go</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/bundle.css">
|
||||
{{ template "header.html" . }}
|
||||
<title>{{ .lang.Strings.pageTitle }}</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="pageContainer">
|
||||
<div class="container">
|
||||
<body class="max-w-full overflow-x-hidden section">
|
||||
<div id="notification-box"></div>
|
||||
<span class="dropdown" tabindex="0" id="lang-dropdown">
|
||||
<span class="button ~urge dropdown-button">
|
||||
<i class="ri-global-line"></i>
|
||||
<span class="ml-1 chev"></span>
|
||||
</span>
|
||||
<div class="dropdown-display">
|
||||
<div class="card ~neutral !low" id="lang-list">
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
<div class="page-container" id="page-container">
|
||||
<div class="card ~neutral !low mb-1">
|
||||
<div class="row">
|
||||
<div class="col-sm"></div>
|
||||
<div id="setupCarousel" class="col-md-auto slider">
|
||||
<div class="slide card text-center" id="page-1">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Welcome!</h5>
|
||||
<p class="card-text">
|
||||
You'll need to do a few things to start using jfa-go. Click below to get started, or quit and edit the config file manually.
|
||||
</p>
|
||||
<a class="btn btn-primary nextButton" href="#page-2">Get Started</a>
|
||||
<img class="banner header" src="banner.svg" alt="jfa-go" />
|
||||
</div>
|
||||
<div class="row col flex center">
|
||||
<span class="heading welcome">{{ .lang.StartPage.welcome }}</span>
|
||||
</div>
|
||||
<div class="row col flex center">
|
||||
<p class="content">{{ .lang.StartPage.pressStart }}</p>
|
||||
</div>
|
||||
<section class="section ~neutral banner footer flex-expand middle">
|
||||
<span class="support">{{ .lang.StartPage.httpsNotice }}</span>
|
||||
<span class="button ~urge !normal next">{{ .lang.StartPage.start }}</span>
|
||||
</section>
|
||||
</div>
|
||||
<div class="card ~neutral !low mb-1 unfocused">
|
||||
<span class="heading">{{ .lang.Language.title }}</span>
|
||||
<p class="content" id="language-description"></p>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.Language.defaultAdminLang }}</span>
|
||||
<div class="select ~neutral !normal mt-half mb-1">
|
||||
<select id="ui-language-admin">
|
||||
</select>
|
||||
</div>
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.Language.defaultFormLang }}</span>
|
||||
<div class="select ~neutral !normal mt-half mb-1">
|
||||
<select id="ui-language-form">
|
||||
</select>
|
||||
</div>
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.Language.defaultEmailLang }}</span>
|
||||
<div class="select ~neutral !normal mt-half mb-1">
|
||||
<select id="email-language">
|
||||
</select>
|
||||
</div>
|
||||
</label>
|
||||
<section class="section ~neutral banner footer flex-expand middle">
|
||||
<span class="button ~neutral !normal back">{{ .lang.Strings.back }}</span>
|
||||
<span class="button ~urge !normal next">{{ .lang.Strings.next }}</span>
|
||||
</section>
|
||||
</div>
|
||||
<div class="card ~neutral !low mb-1 unfocused">
|
||||
<span class="heading">{{ .lang.General.title }}</span>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.General.listenAddress }}</span>
|
||||
<input type="url" class="input ~neutral !normal mt-half mb-1" id="ui-host" value="0.0.0.0">
|
||||
</label>
|
||||
<label class="row switch">
|
||||
<input type="checkbox" id="advanced-tls"><span>{{ .lang.General.useHTTPS }}</span>
|
||||
</label>
|
||||
<p class="support mb-1">{{ .lang.General.useHTTPSNotice }}</p>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.General.pathToCertificate }}</span>
|
||||
<input type="text" class="input ~neutral !normal mt-half mb-1" id="advanced-tls_cert">
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.General.pathToKeyFile }}</span>
|
||||
<input type="text" class="input ~neutral !normal mt-half mb-1" id="advanced-tls_key">
|
||||
</label>
|
||||
<span class="heading">{{ .lang.Updates.title }}</span>
|
||||
<p class="content" id="updates-description"></p>
|
||||
<label class="row switch pb-1">
|
||||
<input type="checkbox" id="updates-enabled" checked><span>{{ .lang.Strings.enabled }}</span>
|
||||
</label>
|
||||
<label class="label">
|
||||
<span>{{ .lang.Updates.updateChannel }}</span>
|
||||
<div class="select ~neutral !normal mt-half mb-1">
|
||||
<select id="updates-channel">
|
||||
<option value="stable">{{ .lang.Updates.stable }}</option>
|
||||
<option value="unstable">{{ .lang.Updates.unstable }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<small>Note: Make sure you are accessing this page through HTTPS, or on a private network.</small>
|
||||
</label>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.Strings.port }}</span>
|
||||
<input type="number" class="input ~neutral !normal mt-half mb-1" id="ui-port" value="8056">
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.General.httpsPort }}</span>
|
||||
<input type="number" class="input ~neutral !normal mt-half mb-1" id="advanced-tls_port" value="8057">
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.General.urlBase }} ({{ .lang.Strings.optional }})</span>
|
||||
<input type="url" class="input ~neutral !normal mt-half" id="ui-url_base">
|
||||
<p class="support mb-1">{{ .lang.General.urlBaseNotice }}</p>
|
||||
</label>
|
||||
<label class="label">
|
||||
<span>{{ .lang.Strings.theme }}</span>
|
||||
<div class="select ~neutral !normal mt-half mb-1">
|
||||
<select id="ui-theme">
|
||||
<option value="Jellyfin (Dark)">{{ .lang.General.darkTheme }}</option>
|
||||
<option value="Default (Light)">{{ .lang.General.lightTheme }}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="slide card" id="page-2">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Login</h5>
|
||||
<p class="card-text">
|
||||
To access the admin page, you'll need to login. Choose how below.
|
||||
<ul>
|
||||
<li><b>Authorize through Jellyfin: </b>Checks credentials with Jellyfin, allowing you to share login details and grant multiple users access.</li>
|
||||
<li><b>Username & Password: </b>Set your own username and password manually.</li>
|
||||
</ul>
|
||||
<div class="form-check" id="jfAuthFormGroup">
|
||||
<input class="form-check-input" type="radio" name="auth" id="jfAuthRadio" value="jfAuth" checked>
|
||||
<label class="form-check-label" for="jfAuthRadio">
|
||||
Authorize through Jellyfin
|
||||
</label>
|
||||
</div>
|
||||
<div id="adminOnlyArea">
|
||||
<div class="form-check" style="margin-left: 1rem;">
|
||||
<input type="checkbox" class="form-check-input" id="jfAuthAdminOnly" checked>
|
||||
<label for="jfAuthAdminOnly" class="form-check-label">Allow admin users only</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="auth" id="manualAuthRadio" value="manualAuth">
|
||||
<label class="form-check-label" for="manualAuthRadio">
|
||||
Manual username & password
|
||||
</label>
|
||||
</div>
|
||||
<div id="manualAuthArea">
|
||||
<div class="form-group">
|
||||
<label for="manualAuthUsername">Username</label>
|
||||
<input type="text" class="form-control" id="manualAuthUsername" placeholder="Username">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="manualAuthPassword">Password</label>
|
||||
<input type="password" class="form-control" id="manualAuthPassword" placeholder="Password">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="manualAuthEmail">Email (Optional)</label>
|
||||
<input type="email" class="form-control" id="manualAuthEmail" placeholder="example@example.com">
|
||||
<small class="form-text text-muted">Your email address is only required if you want to recieve activity notifications.</small>
|
||||
</div>
|
||||
</div>
|
||||
</p>
|
||||
<div class="btn-group float-right" role="group" aria-label="Back/Next buttons">
|
||||
<a class="btn btn-secondary backButton" href="#page-1">Back</a>
|
||||
<a class="btn btn-primary nextButton" href="#page-3">Next</a>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<section class="section ~neutral banner footer flex-expand middle">
|
||||
<span class="button ~neutral !normal back">{{ .lang.Strings.back }}</span>
|
||||
<span class="button ~urge !normal next">{{ .lang.Strings.next }}</span>
|
||||
</section>
|
||||
</div>
|
||||
<div class="card ~neutral !low mb-1 unfocused">
|
||||
<span class="heading">{{ .lang.Login.title }}</span>
|
||||
<p class="content">{{ .lang.Login.description }}</p>
|
||||
<div class="pl-1">
|
||||
<label class="row switch pb-1">
|
||||
<input type="radio" name="ui-jellyfin_login" value="true" checked><span>{{ .lang.Login.authorizeWithJellyfin }}</span>
|
||||
</label>
|
||||
<label class="row switch pl-1 pb-1">
|
||||
<input type="checkbox" id="ui-admin_only"><span>{{ .lang.Login.adminOnly }}</span>
|
||||
</label>
|
||||
<label class="row switch pb-1">
|
||||
<input type="radio" name="ui-jellyfin_login" value="false"><span>{{ .lang.Login.authorizeManual }}</span>
|
||||
</label>
|
||||
</div>
|
||||
<div id="login-manual">
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.Strings.username }}</span>
|
||||
<input type="text" id="ui-username" class="input ~neutral !normal mt-half mb-1" placeholder="{{ .lang.Strings.username }}">
|
||||
</label>
|
||||
<label class="label">
|
||||
<span>{{ .lang.Strings.password }}</span>
|
||||
<input type="password" id="ui-password" class="input ~neutral !normal mt-half mb-1" placeholder="{{ .lang.Strings.password }}">
|
||||
</label>
|
||||
<label class="label">
|
||||
<span>{{ .lang.Strings.emailAddress }} ({{ .lang.Strings.optional }})</span>
|
||||
<input type="email" id="ui-email" class="input ~neutral !normal mt-half" placeholder="email@address">
|
||||
<span class="support mb-1">{{ .lang.Login.emailNotice }}</span>
|
||||
</label>
|
||||
</div>
|
||||
<section class="section ~neutral banner footer flex-expand middle">
|
||||
<span class="button ~neutral !normal back">{{ .lang.Strings.back }}</span>
|
||||
<span class="button ~urge !normal next">{{ .lang.Strings.next }}</span>
|
||||
</section>
|
||||
</div>
|
||||
<div class="card ~neutral !low mb-1 unfocused">
|
||||
<span class="heading">{{ .lang.JellyfinEmby.title }}</span>
|
||||
<p class="content">{{ .lang.JellyfinEmby.description }}</p>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<label class="label">
|
||||
<span>{{ .lang.Strings.serverType }}</span>
|
||||
<div class="select ~neutral !normal mt-half">
|
||||
<select id="jellyfin-type">
|
||||
<option value="jellyfin">Jellyfin</option>
|
||||
<option value="emby">Emby</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="slide card" id="page-3">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Jellyfin</h5>
|
||||
<p class="card-text">
|
||||
jfa-go needs admin access so that it can create users, as this is currently not permitted via API tokens.
|
||||
You should create a separate account for it, checking 'Allow this user to manage the server'. You can disable everything else. Once done, enter the credentials here.
|
||||
<div class="form-group">
|
||||
<label for="jfHost">Host (For internal use)</label>
|
||||
<input type="url" class="form-control" id="jfHost" placeholder="http://jellyf.in:443" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="jfPublicHost">Public Host (For access by users)</label>
|
||||
<input type="url" class="form-control" id="jfPublicHost" placeholder="Leave blank to use the above address.">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="jfUser">Username</label>
|
||||
<input type="text" class="form-control" id="jfUser" placeholder="Username" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="jfPassword">Password</label>
|
||||
<input type="password" class="form-control" id="jfPassword" placeholder="Password" required>
|
||||
</div>
|
||||
<div style="margin-top: 1rem;">
|
||||
<button class="btn btn-secondary" id="jfTestButton">Test</button>
|
||||
<div class="btn-group float-right" role="group" aria-label="Back/Next buttons">
|
||||
<a class="btn btn-secondary backButton" href="#page-2">Back</a>
|
||||
<a class="btn btn-primary nextButton disabled" id="jfNextButton" aria-disabled="true" href="#page-4">Next</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="slide card" id="page-4">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Email</h5>
|
||||
<p class="card-text">jfa-go is capable of sending a PIN code when a user tries to reset their password on Jellyfin. One can also choose to send an invite code directly to an email address. This can be done through SMTP or through <a href="https://www.mailgun.com/">Mailgun's</a> API.
|
||||
<div class="form-group">
|
||||
<div class="form-check" id="emailDisabled">
|
||||
<input class="form-check-input" type="radio" name="email" id="emailDisabledRadio" value="emailDisabled">
|
||||
<label class="form-check-label" for="emailDisabledRadio">
|
||||
Disabled
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check" id="emailSMTP">
|
||||
<input class="form-check-input" type="radio" name="email" id="emailSMTPRadio" value="emailSMTP" checked>
|
||||
<label class="form-check-label" for="emailSMTPRadio">
|
||||
SMTP
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="email" id="emailMailgunRadio" value="emailMailgun">
|
||||
<label class="form-check-label" for="emailMailgunRadio">
|
||||
Mailgun API
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div id="emailSMTPArea">
|
||||
<div class="form-group form-check form-switch">
|
||||
<input type="checkbox" class="form-check-input" id="emailSSL_TLS" checked>
|
||||
<label for="emailSSL_TLS" class="form-check-label" id="emailSSL_TLSLabel">Use SSL/TLS</label>
|
||||
<small class="form-text text-muted">Note: SSL/TLS usually uses port 465, whereas STARTTLS usually uses 587.</small>
|
||||
</div>
|
||||
<div class="form-group form-row">
|
||||
<div class="col">
|
||||
<input type="text" class="form-control" id="emailSMTPServer" placeholder="SMTP Server Address">
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="number" class="form-control" id="emailSMTPPort" placeholder="Port">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group form-row">
|
||||
<div class="col">
|
||||
<input type="email" class="form-control" id="emailSMTPAddress" placeholder="jellyfin@jellyf.in">
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="password" class="form-control" id="emailSMTPPassword" placeholder="Password">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="emailMailgunArea">
|
||||
<div class="form-group">
|
||||
<input type="url" class="form-control" id="emailMailgunURL" placeholder="API URL">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="password" class="form-control" id="emailMailgunKey" placeholder="API Key">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="email" class="form-control" id="emailMailgunAddress" placeholder="jellyfin@jellyf.in">
|
||||
</div>
|
||||
</div>
|
||||
<div id="emailCommonArea">
|
||||
<h5 class="card-title">Notifications</h5>
|
||||
<p class="card-text">Enabling notifications will allow you to choose (per-invite) to recieve emails when an invite expires, or when a new user is created. If you chose to use Manual auth instead of Jellyfin auth previously, make sure you provided an email address.</p>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" id="notificationsEnabled">
|
||||
<label for="notificationsEnabled" class="form-check-label">Enabled</label>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</p>
|
||||
<div class="btn-group float-right" role="group" aria-label="Back/Next buttons">
|
||||
<a class="btn btn-secondary backButton" href="#page-3">Back</a>
|
||||
<a class="btn btn-primary nextButton" id="emailNextButton" href="#page-5">Next</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="slide card" id="page-5">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Email</h5>
|
||||
<p class="card-text">Just a few more things to get your emails looking great.
|
||||
<div class="form-group">
|
||||
<label for="emailSender">Sender: The name shown when a user receives an email.</label>
|
||||
<input type="text" class="form-control" id="emailSender" value="Jellyfin">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="emailDateFormat">Date Format: Follows <a target="_blank" href="https://strftime.org/">strftime</a> format.</label>
|
||||
<input type="text" class="form-control" id="emailDateFormat" value="%d/%m/%y">
|
||||
</div>
|
||||
<div class="form-group form-check">
|
||||
<input class="form-check-input" type="radio" name="time" id="email24hTimeRadio" value="email24hTime" checked>
|
||||
<label class="form-check-label" for="email24hTimeRadio">24h time</label>
|
||||
</div>
|
||||
<div class="form-group form-check">
|
||||
<input class="form-check-input" type="radio" name="time" id="email12hTimeRadio" value="email12hTime">
|
||||
<label class="form-check-label" for="email12hTimeRadio">12h time</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="emailMessage">Message: Short message displayed at the bottom of emails.</label>
|
||||
<input type="text" class="form-control" id="emailMessage" value="Need help? Contact me.">
|
||||
</div>
|
||||
</p>
|
||||
<div class="btn-group float-right" role="group" aria-label="Back/Next buttons">
|
||||
<a class="btn btn-secondary backButton" href="#page-4">Back</a>
|
||||
<a class="btn btn-primary nextButton" href="#page-6">Next</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="slide card" id="page-6">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Password Resets</h5>
|
||||
<p class="card-text">
|
||||
When a user tries to reset their password in jellyfin, it informs them that a file has been created, named "passwordreset*.json" where * is a number. jfa-go will then read this file, and send the PIN to the user's email. Try it now, and put the folder that it informs you it put the file in below. Also, if enter a custom email subject if you don't like the default one.
|
||||
</p>
|
||||
<div class="form-group form-check">
|
||||
<input type="checkbox" class="form-check-input" id="pwrEnabled" value="enabled">
|
||||
<label class="form-check-label" for="pwrEnabled">Enabled</label>
|
||||
</div>
|
||||
<div id="pwrArea">
|
||||
<div class="form-group">
|
||||
<label for="pwrJfPath">Path to Jellyfin</label>
|
||||
<input type="text" class="form-control" id="pwrJfPath" placeholder="Folder">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="pwrSubject">Email Subject</label>
|
||||
<input type="text" class="form-control" id="pwrSubject" value="Password Reset - Jellyfin">
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn-group float-right" role="group" aria-label="Back/Next buttons">
|
||||
<a class="btn btn-secondary backButton" href="#page-5">Back</a>
|
||||
<a class="btn btn-primary nextButton" href="#page-7">Next</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="slide card" id="page-7">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Invite Emails</h5>
|
||||
<p class="card-text">
|
||||
Allows you to send an invite code directly to a specified email address.
|
||||
Since you'll most likely being running this behind a reverse proxy, the program has no way of knowing the address it will be accessed from. This is needed for sending emails with links. Write your URL Base with the protocol and append '/invite', e.g:
|
||||
<ul>
|
||||
<li>On the local network, you might use <a href="#">http://localhost:8056/invite</a></li>
|
||||
<li>Exposed to the internet, you might use <a href="#">https://accounts.jellyf.in/invite</a></li>
|
||||
</ul>
|
||||
</p>
|
||||
<div class="form-group form-check">
|
||||
<input type="checkbox" class="form-check-input" id="invEnabled" value="enabled" checked>
|
||||
<label class="form-check-label" for="invEnabled">Enabled</label>
|
||||
</div>
|
||||
<div id="invArea">
|
||||
<div class="form-group">
|
||||
<label for="invURLBase">URL Base</label>
|
||||
<input type="url" class="form-control" id="invURLBase" placeholder="https://accounts.jellyf.in/invite">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="invSubject">Subject</label>
|
||||
<input type="text" class="form-control" id="invSubject" value="Invite - Jellyfin">
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn-group float-right" role="group" aria-label="Back/Next buttons">
|
||||
<a class="btn btn-secondary backButton" href="#page-6">Back</a>
|
||||
<a class="btn btn-primary nextButton" href="#page-8">Next</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="slide card" id="page-8">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Password Validation</h5>
|
||||
<p class="card-text">
|
||||
Enabling this will display a set of password requirements on the create account page, such as minimum length, uppercase characters, special characters, etc.
|
||||
</p>
|
||||
<div class="form-group form-check">
|
||||
<input type="checkbox" class="form-check-input" id="valEnabled" value="enabled">
|
||||
<label class="form-check-label" for="valEnabled">Enabled</label>
|
||||
</div>
|
||||
<div id="valArea">
|
||||
<div class="form-group">
|
||||
<label for="valLength">Minimum Length</label>
|
||||
<input type="number" class="form-control" id="valLength" value="8">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="valUpper">Minimum number of uppercase characters</label>
|
||||
<input type="number" class="form-control" id="valUpper" value="1">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="valLower">Minimum number of lowercase characters</label>
|
||||
<input type="number" class="form-control" id="valLower" value="0">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="valNumber">Minimum number of numbers</label>
|
||||
<input type="number" class="form-control" id="valNumber" value="0">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="valSpecial">Minimum number of special characters</label>
|
||||
<input type="number" class="form-control" id="valSpecial" value="0">
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn-group float-right" role="group" aria-label="Back/Next buttons">
|
||||
<a class="btn btn-secondary backButton" id="valBackButton" href="#page-7">Back</a>
|
||||
<a class="btn btn-primary nextButton" href="#page-9">Next</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="slide card" id="page-9">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Help Messages</h5>
|
||||
<p class="card-text">
|
||||
Just a few little messages that will display in various places. Leave these alone if you want.
|
||||
</p>
|
||||
<div class="form-group">
|
||||
<label for="msgContact">Contact message: Displays at bottom of all pages (except admin).</label>
|
||||
<input id="msgContact" type="text" class="form-control" value="Need help? Contact me.">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="msgHelp">Help message: Displays when a user is creating an account.</label>
|
||||
<input id="msgHelp" type="text" class="form-control" value="Enter your details to create an account.">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="msgSuccess">Success message: Displays when a user successfully creates an account, just above a button taking the user to Jellyfin.</label>
|
||||
<input id="msgSuccess" type="text" class="form-control" value="Your account has been created. Click below to continue to Jellyfin.">
|
||||
</div>
|
||||
<div class="btn-group float-right" role="group" aria-label="Back/Next buttons">
|
||||
<a class="btn btn-secondary backButton" href="#page-8">Back</a>
|
||||
<a class="btn btn-primary nextButton" href="#page-10">Next</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="slide card" id="page-10">
|
||||
<div class="card-body text-center">
|
||||
<h5 class="card-title">Finished!</h5>
|
||||
<p class="card-text">
|
||||
Press the button below to submit your settings. The program will restart. Once it's done, refresh this page.
|
||||
</p>
|
||||
<button id="submitButton" class="btn btn-primary">Submit</button>
|
||||
<p class="support mb-1">{{ .lang.JellyfinEmby.embyNotice }}</p>
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.JellyfinEmby.replaceJellyfin }} ({{ .lang.Strings.optional }})</span>
|
||||
<input type="text" class="input ~neutral !normal mt-half" id="jellyfin-substitute_jellyfin_strings">
|
||||
<p class="support mb-1">{{ .lang.JellyfinEmby.replaceJellyfinNotice }}</p>
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.Strings.username }}</span>
|
||||
<input type="text" id="jellyfin-username" class="input ~neutral !normal mt-half mb-1" placeholder="{{ .lang.Strings.username }}">
|
||||
</label>
|
||||
<label class="label">
|
||||
<span>{{ .lang.Strings.password }}</span>
|
||||
<input type="password" id="jellyfin-password" class="input ~neutral !normal mt-half mb-1" placeholder="{{ .lang.Strings.password }}">
|
||||
</label>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.Strings.serverAddress }} ({{ .lang.JellyfinEmby.internal }})</span>
|
||||
<input type="url" class="input ~neutral !normal mt-half mb-1" id="jellyfin-server" placeholder="http://jellyf.in:80">
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.Strings.serverAddress }} ({{ .lang.JellyfinEmby.external }})</span>
|
||||
<input type="url" class="input ~neutral !normal mt-half" id="jellyfin-public_server" placeholder="https://jellyf.in">
|
||||
<p class="support mb-1">{{ .lang.JellyfinEmby.addressExternalNotice }}</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<section class="section ~neutral banner footer flex-expand middle">
|
||||
<span class="button ~neutral !normal back">{{ .lang.Strings.back }}</span>
|
||||
<div>
|
||||
<span class="button ~urge !normal" id="jellyfin-test-connection">{{ .lang.JellyfinEmby.testConnection }}</span>
|
||||
<span class="button ~urge !normal next" disabled>{{ .lang.Strings.next }}</span>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<div class="card ~neutral !low mb-1 unfocused">
|
||||
<span class="heading">{{ .lang.Ombi.title }}</span>
|
||||
<p class="content">{{ .lang.Ombi.description }}</p>
|
||||
<label class="row switch pb-1">
|
||||
<input type="checkbox" id="ombi-enabled"><span>{{ .lang.Strings.enabled }}</span>
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.Strings.serverAddress }}</span>
|
||||
<input type="url" class="input ~neutral !normal mt-half mb-1" id="ombi-server" placeholder="ombi.jellyf.in">
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.Strings.apiKey }}</span>
|
||||
<input type="text" class="input ~neutral !normal mt-half" id="ombi-api_key">
|
||||
<p class="support mb-1">{{ .lang.Ombi.apiKeyNotice }}</p>
|
||||
</label>
|
||||
<section class="section ~neutral banner footer flex-expand middle">
|
||||
<span class="button ~neutral !normal back">{{ .lang.Strings.back }}</span>
|
||||
<div>
|
||||
<span class="button ~urge !normal next">{{ .lang.Strings.next }}</span>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<div class="card ~neutral !low mb-1 unfocused">
|
||||
<span class="heading">{{ .lang.Email.title }}</span>
|
||||
<p class="content" id="email-description"></p>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<label class="label">
|
||||
<span>{{ .lang.Email.method }}</span>
|
||||
<div class="select ~neutral !normal mt-half mb-1">
|
||||
<select id="email-method">
|
||||
<option value="">{{ .lang.Strings.disabled }}</option>
|
||||
<option value="smtp">SMTP</option>
|
||||
<option value="mailgun">Mailgun</option>
|
||||
</select>
|
||||
</div>
|
||||
</label>
|
||||
<label class="row switch">
|
||||
<input type="checkbox" id="email-no_username"><span>{{ .lang.Email.useEmailAsUsername }}</span>
|
||||
<p class="support mb-1">{{ .lang.Email.useEmailAsUsernameNotice }}</p>
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.Email.fromAddress }}</span>
|
||||
<input type="email" class="input ~neutral !normal mt-half mb-1" id="email-address" placeholder="mail@jellyf.in">
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.Email.senderName }}</span>
|
||||
<input type="text" class="input ~neutral !normal mt-half mb-1" id="email-from" value="Jellyfin">
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.Email.dateFormat }}</span>
|
||||
<input type="text" class="input ~neutral !normal mt-half" id="email-date_format" value="%d/%m/%y">
|
||||
<p class="support mb-1" id="email-dateformat-notice"></p>
|
||||
</label>
|
||||
<div>
|
||||
<label class="row switch pb-1">
|
||||
<input type="radio" name="email-24h" value="true" checked><span>{{ .lang.Strings.time24h }}</span>
|
||||
</label>
|
||||
<label class="row switch pb-1">
|
||||
<input type="radio" name="email-24h" value="false"><span>{{ .lang.Strings.time12h }}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm"></div>
|
||||
<div class="col">
|
||||
<div id="email-smtp">
|
||||
<p class="subheading">SMTP</p>
|
||||
<label class="label">
|
||||
<span>{{ .lang.Email.encryption }}</span>
|
||||
<div class="select ~neutral !normal mt-half mb-1">
|
||||
<select id="smtp-encryption">
|
||||
<option value="starttls">STARTTLS ({{ .lang.Strings.port }} 587)</option>
|
||||
<option value="ssl_tls">SSL/TLS ({{ .lang.Strings.port }} 465)</option>
|
||||
</select>
|
||||
</div>
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.Strings.serverAddress }}</span>
|
||||
<input type="url" class="input ~neutral !normal mt-half mb-1" id="smtp-server" placeholder="smtp.jellyf.in">
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.Strings.port }}</span>
|
||||
<input type="number" class="input ~neutral !normal mt-half mb-1" id="smtp-port" placeholder="587">
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.Strings.username }}</span>
|
||||
<input type="text" class="input ~neutral !normal mt-half mb-1" id="smtp-username">
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.Strings.password }}</span>
|
||||
<input type="password" class="input ~neutral !normal mt-half mb-1" id="smtp-password">
|
||||
</label>
|
||||
</div>
|
||||
<div id="email-mailgun">
|
||||
<p class="subheading">Mailgun</p>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.Email.mailgunApiURL }}</span>
|
||||
<input type="url" class="input ~neutral !normal mt-half mb-1" id="mailgun-api_url" placeholder="https://api.eu.mailgun.net/v3/mail.jellyf.in/messages">
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.Strings.apiKey }}</span>
|
||||
<input type="text" class="input ~neutral !normal mt-half mb-1" id="mailgun-api_key">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<section class="section ~neutral banner footer flex-expand middle">
|
||||
<span class="button ~neutral !normal back">{{ .lang.Strings.back }}</span>
|
||||
<div>
|
||||
<span class="button ~urge !normal next">{{ .lang.Strings.next }}</span>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<div class="card ~neutral !low mb-1 unfocused related-to-email">
|
||||
<span class="heading">{{ .lang.Notifications.title }}</span>
|
||||
<p class="content">{{ .lang.Notifications.description }}</p>
|
||||
<label class="row switch pb-1">
|
||||
<input type="checkbox" id="notifications-enabled"><span>{{ .lang.Strings.enabled }}</span>
|
||||
</label>
|
||||
<span class="heading">{{ .lang.WelcomeEmails.title }}</span>
|
||||
<p class="content">{{ .lang.WelcomeEmails.description }}</p>
|
||||
<label class="row switch pb-1">
|
||||
<input type="checkbox" id="welcome_email-enabled"><span>{{ .lang.Strings.enabled }}</span>
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.Strings.emailSubject }}</span>
|
||||
<input type="text" class="input ~neutral !normal mt-half mb-1" id="welcome_email-subject" placeholder="{{ .emailLang.WelcomeEmail.title }}">
|
||||
</label>
|
||||
<section class="section ~neutral banner footer flex-expand middle">
|
||||
<span class="button ~neutral !normal back">{{ .lang.Strings.back }}</span>
|
||||
<div>
|
||||
<span class="button ~urge !normal next">{{ .lang.Strings.next }}</span>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<div class="card ~neutral !low mb-1 unfocused related-to-email">
|
||||
<span class="heading">{{ .lang.InviteEmails.title }}</span>
|
||||
<p class="content">{{ .lang.InviteEmails.description }}</p>
|
||||
<label class="row switch pb-1">
|
||||
<input type="checkbox" id="invite_emails-enabled"><span>{{ .lang.Strings.enabled }}</span>
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.Strings.URL }}</span>
|
||||
<input type="url" class="input ~neutral !normal mt-half mb-1" id="invite_emails-url_base" placeholder="https://accounts.jellyf.in/invite">
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.Strings.emailSubject }}</span>
|
||||
<input type="text" class="input ~neutral !normal mt-half mb-1" id="invite_emails-subject" placeholder="{{ .emailLang.InviteEmail.title }}">
|
||||
</label>
|
||||
<section class="section ~neutral banner footer flex-expand middle">
|
||||
<span class="button ~neutral !normal back">{{ .lang.Strings.back }}</span>
|
||||
<div>
|
||||
<span class="button ~urge !normal next">{{ .lang.Strings.next }}</span>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<div id="password-resets" class="card ~neutral !low mb-1 unfocused related-to-email">
|
||||
<span class="heading">{{ .lang.PasswordResets.title }}</span>
|
||||
<p class="content">{{ .lang.PasswordResets.description }}</p>
|
||||
<label class="row switch pb-1">
|
||||
<input type="checkbox" id="password_resets-enabled"><span>{{ .lang.Strings.enabled }}</span>
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.PasswordResets.pathToJellyfin }}</span>
|
||||
<input type="text" class="input ~neutral !normal mt-half" id="password_resets-watch_directory" placeholder="/config/jellyfin">
|
||||
<p class="support mb-1">{{ .lang.PasswordResets.pathToJellyfinNotice }}</p>
|
||||
</label>
|
||||
<label class="switch">
|
||||
<input type="checkbox" id="password_resets-link_reset"><span>{{ .lang.PasswordResets.resetLinks }}</span>
|
||||
<p class="support mb-1">{{ .lang.PasswordResets.resetLinksNotice }}</p>
|
||||
</label>
|
||||
<label class="row label">
|
||||
<p class="mt-half">{{ .lang.PasswordResets.resetLinksLanguage }}</p>
|
||||
<div class="select ~neutral !normal mt-half mb-1">
|
||||
<select id="password_resets-language">
|
||||
</select>
|
||||
</div>
|
||||
</label>
|
||||
<label class="row label">
|
||||
<span class="mt-half">{{ .lang.Strings.emailSubject }}</span>
|
||||
<input type="text" class="input ~neutral !normal mt-half mb-1" id="password_resets-subject" placeholder="{{ .emailLang.PasswordReset.title }}">
|
||||
</label>
|
||||
<section class="section ~neutral banner footer flex-expand middle">
|
||||
<span class="button ~neutral !normal back">{{ .lang.Strings.back }}</span>
|
||||
<div>
|
||||
<span class="button ~urge !normal next">{{ .lang.Strings.next }}</span>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<div class="card ~neutral !low mb-1 unfocused">
|
||||
<span class="heading">{{ .lang.PasswordValidation.title }}</span>
|
||||
<p class="content">{{ .lang.PasswordValidation.description }}</p>
|
||||
<label class="row switch pb-1">
|
||||
<input type="checkbox" id="password_validation-enabled" checked><span>{{ .lang.Strings.enabled }}</span>
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.PasswordValidation.length }}</span>
|
||||
<input type="number" class="input ~neutral !normal mt-half mb-1" id="password_validation-min_length" value="8">
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.PasswordValidation.uppercase }}</span>
|
||||
<input type="number" class="input ~neutral !normal mt-half mb-1" id="password_validation-upper" value="1">
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.PasswordValidation.lowercase }}</span>
|
||||
<input type="number" class="input ~neutral !normal mt-half mb-1" id="password_validation-lower" value="0">
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.PasswordValidation.numbers }}</span>
|
||||
<input type="number" class="input ~neutral !normal mt-half mb-1" id="password_validation-number" value="0">
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.PasswordValidation.special }}</span>
|
||||
<input type="number" class="input ~neutral !normal mt-half mb-1" id="password_validation-special" value="0">
|
||||
</label>
|
||||
<section class="section ~neutral banner footer flex-expand middle">
|
||||
<span class="button ~neutral !normal back">{{ .lang.Strings.back }}</span>
|
||||
<div>
|
||||
<span class="button ~urge !normal next">{{ .lang.Strings.next }}</span>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<div class="card ~neutral !low mb-1 unfocused">
|
||||
<span class="heading">{{ .lang.HelpMessages.title }}</span>
|
||||
<p class="content">{{ .lang.HelpMessages.description }}</p>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.HelpMessages.contactMessage }}</span>
|
||||
<input type="text" class="input ~neutral !normal mt-half" id="ui-contact_message">
|
||||
<p class="support mb-1">{{ .lang.HelpMessages.contactMessageNotice }}</p>
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.HelpMessages.helpMessage }}</span>
|
||||
<input type="text" class="input ~neutral !normal mt-half" id="ui-help_message">
|
||||
<p class="support mb-1">{{ .lang.HelpMessages.helpMessageNotice }}</p>
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-half">{{ .lang.HelpMessages.successMessage }}</span>
|
||||
<input type="text" class="input ~neutral !normal mt-half" id="ui-success_message">
|
||||
<p class="support mb-1">{{ .lang.HelpMessages.successMessageNotice }}</p>
|
||||
</label>
|
||||
<label class="label related-to-email">
|
||||
<span class="mt-half">{{ .lang.HelpMessages.emailMessage }}</span>
|
||||
<input type="text" class="input ~neutral !normal mt-half" id="email-message">
|
||||
<p class="support mb-1">{{ .lang.HelpMessages.emailMessageNotice }}</p>
|
||||
</label>
|
||||
<section class="section ~neutral banner footer flex-expand middle">
|
||||
<span class="button ~neutral !normal back">{{ .lang.Strings.back }}</span>
|
||||
<div>
|
||||
<span class="button ~urge !normal next">{{ .lang.Strings.next }}</span>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<div class="card ~neutral !low mb-1 unfocused">
|
||||
<div class="row col flex center">
|
||||
<span class="heading">{{ .lang.EndPage.finished }}</span>
|
||||
</div>
|
||||
<div class="row col flex center">
|
||||
<p class="content">{{ .lang.EndPage.restartMessage }}</p>
|
||||
</div>
|
||||
<div class="row col flex center">
|
||||
<span class="button ~neutral !normal back mr-1">{{ .lang.Strings.back }}</span>
|
||||
<span class="button ~urge !normal" id="restart">{{ .lang.Strings.submit }}</span>
|
||||
<span class="button ~urge !normal unfocused" id="refresh">{{ .lang.EndPage.refreshPage }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="js/setup.js"></script>
|
||||
<script>
|
||||
window.langFile = JSON.parse({{ .language }});
|
||||
window.messages = JSON.parse({{ .messages }});
|
||||
</script>
|
||||
<script src="js/setup.js" type="module"></script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 66 KiB |
BIN
images/demo.gif
|
Before Width: | Height: | Size: 2.4 MiB After Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 83 KiB |
42
internal.go
Normal file
@@ -0,0 +1,42 @@
|
||||
// +build !external
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"io/fs"
|
||||
"log"
|
||||
)
|
||||
|
||||
const binaryType = "internal"
|
||||
|
||||
//go:embed data data/html data/web data/web/css data/web/js
|
||||
var loFS embed.FS
|
||||
|
||||
//go:embed lang/common lang/admin lang/email lang/form lang/setup lang/pwreset lang/telegram
|
||||
var laFS embed.FS
|
||||
|
||||
var langFS rewriteFS
|
||||
var localFS rewriteFS
|
||||
|
||||
type rewriteFS struct {
|
||||
fs embed.FS
|
||||
prefix string
|
||||
}
|
||||
|
||||
func (l rewriteFS) Open(name string) (fs.File, error) { return l.fs.Open(l.prefix + name) }
|
||||
func (l rewriteFS) ReadDir(name string) ([]fs.DirEntry, error) { return l.fs.ReadDir(l.prefix + name) }
|
||||
func (l rewriteFS) ReadFile(name string) ([]byte, error) { return l.fs.ReadFile(l.prefix + name) }
|
||||
func FSJoin(elem ...string) string {
|
||||
out := ""
|
||||
for _, v := range elem {
|
||||
out += v + "/"
|
||||
}
|
||||
return out[:len(out)-1]
|
||||
}
|
||||
|
||||
func loadFilesystems() {
|
||||
langFS = rewriteFS{laFS, "lang/"}
|
||||
localFS = rewriteFS{loFS, "data/"}
|
||||
log.Println("Using internal storage")
|
||||
}
|
||||
8
jfa-go.service
Normal file
@@ -0,0 +1,8 @@
|
||||
[Unit]
|
||||
Description=An account management system for Jellyfin.
|
||||
|
||||
[Service]
|
||||
ExecStart={executable}
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
@@ -1,7 +0,0 @@
|
||||
module github.com/hrfee/jfa-go/jfapi
|
||||
|
||||
go 1.15
|
||||
|
||||
replace github.com/hrfee/jfa-go/common => ../common
|
||||
|
||||
require github.com/hrfee/jfa-go/common v0.0.0-00010101000000-000000000000
|
||||
370
jfapi/jfapi.go
@@ -1,370 +0,0 @@
|
||||
package jfapi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hrfee/jfa-go/common"
|
||||
)
|
||||
|
||||
type serverInfo struct {
|
||||
LocalAddress string `json:"LocalAddress"`
|
||||
Name string `json:"ServerName"`
|
||||
Version string `json:"Version"`
|
||||
OS string `json:"OperatingSystem"`
|
||||
ID string `json:"Id"`
|
||||
}
|
||||
|
||||
// Jellyfin represents a running Jellyfin instance.
|
||||
type Jellyfin struct {
|
||||
Server string
|
||||
client string
|
||||
version string
|
||||
device string
|
||||
deviceID string
|
||||
useragent string
|
||||
auth string
|
||||
header map[string]string
|
||||
ServerInfo serverInfo
|
||||
Username string
|
||||
password string
|
||||
Authenticated bool
|
||||
AccessToken string
|
||||
userID string
|
||||
httpClient *http.Client
|
||||
loginParams map[string]string
|
||||
userCache []map[string]interface{}
|
||||
CacheExpiry time.Time
|
||||
cacheLength int
|
||||
noFail bool
|
||||
Hyphens bool
|
||||
timeoutHandler common.TimeoutHandler
|
||||
}
|
||||
|
||||
// NewJellyfin returns a new Jellyfin object.
|
||||
func NewJellyfin(server, client, version, device, deviceID string, timeoutHandler common.TimeoutHandler, cacheTimeout int) (*Jellyfin, error) {
|
||||
jf := &Jellyfin{}
|
||||
jf.Server = server
|
||||
jf.client = client
|
||||
jf.version = version
|
||||
jf.device = device
|
||||
jf.deviceID = deviceID
|
||||
jf.useragent = fmt.Sprintf("%s/%s", client, version)
|
||||
jf.timeoutHandler = timeoutHandler
|
||||
jf.auth = fmt.Sprintf("MediaBrowser Client=\"%s\", Device=\"%s\", DeviceId=\"%s\", Version=\"%s\"", client, device, deviceID, version)
|
||||
jf.header = map[string]string{
|
||||
"Accept": "application/json",
|
||||
"Content-type": "application/json; charset=UTF-8",
|
||||
"X-Application": jf.useragent,
|
||||
"Accept-Charset": "UTF-8,*",
|
||||
"Accept-Encoding": "gzip",
|
||||
"User-Agent": jf.useragent,
|
||||
"X-Emby-Authorization": jf.auth,
|
||||
}
|
||||
jf.httpClient = &http.Client{
|
||||
Timeout: 10 * time.Second,
|
||||
}
|
||||
infoURL := fmt.Sprintf("%s/System/Info/Public", server)
|
||||
req, _ := http.NewRequest("GET", infoURL, nil)
|
||||
resp, err := jf.httpClient.Do(req)
|
||||
defer jf.timeoutHandler()
|
||||
if err == nil {
|
||||
data, _ := ioutil.ReadAll(resp.Body)
|
||||
json.Unmarshal(data, &jf.ServerInfo)
|
||||
}
|
||||
jf.cacheLength = cacheTimeout
|
||||
jf.CacheExpiry = time.Now()
|
||||
return jf, nil
|
||||
}
|
||||
|
||||
// Authenticate attempts to authenticate using a username & password
|
||||
func (jf *Jellyfin) Authenticate(username, password string) (map[string]interface{}, int, error) {
|
||||
jf.Username = username
|
||||
jf.password = password
|
||||
jf.loginParams = map[string]string{
|
||||
"Username": username,
|
||||
"Pw": password,
|
||||
"Password": password,
|
||||
}
|
||||
buffer := &bytes.Buffer{}
|
||||
encoder := json.NewEncoder(buffer)
|
||||
encoder.SetEscapeHTML(false)
|
||||
err := encoder.Encode(jf.loginParams)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
// loginParams, _ := json.Marshal(jf.loginParams)
|
||||
url := fmt.Sprintf("%s/Users/authenticatebyname", jf.Server)
|
||||
req, err := http.NewRequest("POST", url, buffer)
|
||||
defer jf.timeoutHandler()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
for name, value := range jf.header {
|
||||
req.Header.Add(name, value)
|
||||
}
|
||||
resp, err := jf.httpClient.Do(req)
|
||||
if err != nil || resp.StatusCode != 200 {
|
||||
return nil, resp.StatusCode, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var data io.Reader
|
||||
switch resp.Header.Get("Content-Encoding") {
|
||||
case "gzip":
|
||||
data, _ = gzip.NewReader(resp.Body)
|
||||
default:
|
||||
data = resp.Body
|
||||
}
|
||||
var respData map[string]interface{}
|
||||
json.NewDecoder(data).Decode(&respData)
|
||||
jf.AccessToken = respData["AccessToken"].(string)
|
||||
user := respData["User"].(map[string]interface{})
|
||||
jf.userID = respData["User"].(map[string]interface{})["Id"].(string)
|
||||
jf.auth = fmt.Sprintf("MediaBrowser Client=\"%s\", Device=\"%s\", DeviceId=\"%s\", Version=\"%s\", Token=\"%s\"", jf.client, jf.device, jf.deviceID, jf.version, jf.AccessToken)
|
||||
jf.header["X-Emby-Authorization"] = jf.auth
|
||||
jf.Authenticated = true
|
||||
return user, resp.StatusCode, nil
|
||||
}
|
||||
|
||||
func (jf *Jellyfin) get(url string, params map[string]string) (string, int, error) {
|
||||
var req *http.Request
|
||||
if params != nil {
|
||||
jsonParams, _ := json.Marshal(params)
|
||||
req, _ = http.NewRequest("GET", url, bytes.NewBuffer(jsonParams))
|
||||
} else {
|
||||
req, _ = http.NewRequest("GET", url, nil)
|
||||
}
|
||||
for name, value := range jf.header {
|
||||
req.Header.Add(name, value)
|
||||
}
|
||||
resp, err := jf.httpClient.Do(req)
|
||||
defer jf.timeoutHandler()
|
||||
if err != nil || resp.StatusCode != 200 {
|
||||
if resp.StatusCode == 401 && jf.Authenticated {
|
||||
jf.Authenticated = false
|
||||
_, _, authErr := jf.Authenticate(jf.Username, jf.password)
|
||||
if authErr == nil {
|
||||
v1, v2, v3 := jf.get(url, params)
|
||||
return v1, v2, v3
|
||||
}
|
||||
}
|
||||
return "", resp.StatusCode, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var data io.Reader
|
||||
encoding := resp.Header.Get("Content-Encoding")
|
||||
switch encoding {
|
||||
case "gzip":
|
||||
data, _ = gzip.NewReader(resp.Body)
|
||||
default:
|
||||
data = resp.Body
|
||||
}
|
||||
buf := new(strings.Builder)
|
||||
io.Copy(buf, data)
|
||||
//var respData map[string]interface{}
|
||||
//json.NewDecoder(data).Decode(&respData)
|
||||
return buf.String(), resp.StatusCode, nil
|
||||
}
|
||||
|
||||
func (jf *Jellyfin) post(url string, data map[string]interface{}, response bool) (string, int, error) {
|
||||
params, _ := json.Marshal(data)
|
||||
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(params))
|
||||
for name, value := range jf.header {
|
||||
req.Header.Add(name, value)
|
||||
}
|
||||
resp, err := jf.httpClient.Do(req)
|
||||
defer jf.timeoutHandler()
|
||||
if err != nil || resp.StatusCode != 200 {
|
||||
if resp.StatusCode == 401 && jf.Authenticated {
|
||||
jf.Authenticated = false
|
||||
_, _, authErr := jf.Authenticate(jf.Username, jf.password)
|
||||
if authErr == nil {
|
||||
v1, v2, v3 := jf.post(url, data, response)
|
||||
return v1, v2, v3
|
||||
}
|
||||
}
|
||||
return "", resp.StatusCode, err
|
||||
}
|
||||
if response {
|
||||
defer resp.Body.Close()
|
||||
var outData io.Reader
|
||||
switch resp.Header.Get("Content-Encoding") {
|
||||
case "gzip":
|
||||
outData, _ = gzip.NewReader(resp.Body)
|
||||
default:
|
||||
outData = resp.Body
|
||||
}
|
||||
buf := new(strings.Builder)
|
||||
io.Copy(buf, outData)
|
||||
return buf.String(), resp.StatusCode, nil
|
||||
}
|
||||
return "", resp.StatusCode, nil
|
||||
}
|
||||
|
||||
// DeleteUser deletes the user corresponding to the provided ID.
|
||||
func (jf *Jellyfin) DeleteUser(userID string) (int, error) {
|
||||
url := fmt.Sprintf("%s/Users/%s", jf.Server, userID)
|
||||
req, _ := http.NewRequest("DELETE", url, nil)
|
||||
for name, value := range jf.header {
|
||||
req.Header.Add(name, value)
|
||||
}
|
||||
resp, err := jf.httpClient.Do(req)
|
||||
defer jf.timeoutHandler()
|
||||
return resp.StatusCode, err
|
||||
}
|
||||
|
||||
// GetUsers returns all (visible) users on the Jellyfin instance.
|
||||
func (jf *Jellyfin) GetUsers(public bool) ([]map[string]interface{}, int, error) {
|
||||
var result []map[string]interface{}
|
||||
var data string
|
||||
var status int
|
||||
var err error
|
||||
if time.Now().After(jf.CacheExpiry) {
|
||||
if public {
|
||||
url := fmt.Sprintf("%s/users/public", jf.Server)
|
||||
data, status, err = jf.get(url, nil)
|
||||
} else {
|
||||
url := fmt.Sprintf("%s/users", jf.Server)
|
||||
data, status, err = jf.get(url, jf.loginParams)
|
||||
}
|
||||
if err != nil || status != 200 {
|
||||
return nil, status, err
|
||||
}
|
||||
json.Unmarshal([]byte(data), &result)
|
||||
jf.userCache = result
|
||||
jf.CacheExpiry = time.Now().Add(time.Minute * time.Duration(jf.cacheLength))
|
||||
if id, ok := result[0]["Id"]; ok {
|
||||
if id.(string)[8] == '-' {
|
||||
jf.Hyphens = true
|
||||
}
|
||||
}
|
||||
return result, status, nil
|
||||
}
|
||||
return jf.userCache, 200, nil
|
||||
}
|
||||
|
||||
// UserByName returns the user corresponding to the provided username.
|
||||
func (jf *Jellyfin) UserByName(username string, public bool) (map[string]interface{}, int, error) {
|
||||
var match map[string]interface{}
|
||||
find := func() (map[string]interface{}, int, error) {
|
||||
users, status, err := jf.GetUsers(public)
|
||||
if err != nil || status != 200 {
|
||||
return nil, status, err
|
||||
}
|
||||
for _, user := range users {
|
||||
if user["Name"].(string) == username {
|
||||
return user, status, err
|
||||
}
|
||||
}
|
||||
return nil, status, err
|
||||
}
|
||||
match, status, err := find()
|
||||
if match == nil {
|
||||
jf.CacheExpiry = time.Now()
|
||||
match, status, err = find()
|
||||
}
|
||||
return match, status, err
|
||||
}
|
||||
|
||||
// UserByID returns the user corresponding to the provided ID.
|
||||
func (jf *Jellyfin) UserByID(userID string, public bool) (map[string]interface{}, int, error) {
|
||||
if jf.CacheExpiry.After(time.Now()) {
|
||||
for _, user := range jf.userCache {
|
||||
if user["Id"].(string) == userID {
|
||||
return user, 200, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
if public {
|
||||
users, status, err := jf.GetUsers(public)
|
||||
if err != nil || status != 200 {
|
||||
return nil, status, err
|
||||
}
|
||||
for _, user := range users {
|
||||
if user["Id"].(string) == userID {
|
||||
return user, status, nil
|
||||
}
|
||||
}
|
||||
return nil, status, err
|
||||
}
|
||||
var result map[string]interface{}
|
||||
var data string
|
||||
var status int
|
||||
var err error
|
||||
url := fmt.Sprintf("%s/users/%s", jf.Server, userID)
|
||||
data, status, err = jf.get(url, jf.loginParams)
|
||||
if err != nil || status != 200 {
|
||||
return nil, status, err
|
||||
}
|
||||
json.Unmarshal([]byte(data), &result)
|
||||
return result, status, nil
|
||||
}
|
||||
|
||||
// NewUser creates a new user with the provided username and password.
|
||||
func (jf *Jellyfin) NewUser(username, password string) (map[string]interface{}, int, error) {
|
||||
url := fmt.Sprintf("%s/Users/New", jf.Server)
|
||||
stringData := map[string]string{
|
||||
"Name": username,
|
||||
"Password": password,
|
||||
}
|
||||
data := make(map[string]interface{})
|
||||
for key, value := range stringData {
|
||||
data[key] = value
|
||||
}
|
||||
response, status, err := jf.post(url, data, true)
|
||||
var recv map[string]interface{}
|
||||
json.Unmarshal([]byte(response), &recv)
|
||||
if err != nil || !(status == 200 || status == 204) {
|
||||
return nil, status, err
|
||||
}
|
||||
return recv, status, nil
|
||||
}
|
||||
|
||||
// SetPolicy sets the access policy for the user corresponding to the provided ID.
|
||||
func (jf *Jellyfin) SetPolicy(userID string, policy map[string]interface{}) (int, error) {
|
||||
url := fmt.Sprintf("%s/Users/%s/Policy", jf.Server, userID)
|
||||
_, status, err := jf.post(url, policy, false)
|
||||
if err != nil || status != 200 {
|
||||
return status, err
|
||||
}
|
||||
return status, nil
|
||||
}
|
||||
|
||||
// SetConfiguration sets the configuration (part of homescreen layout) for the user corresponding to the provided ID.
|
||||
func (jf *Jellyfin) SetConfiguration(userID string, configuration map[string]interface{}) (int, error) {
|
||||
url := fmt.Sprintf("%s/Users/%s/Configuration", jf.Server, userID)
|
||||
_, status, err := jf.post(url, configuration, false)
|
||||
return status, err
|
||||
}
|
||||
|
||||
// GetDisplayPreferences gets the displayPreferences (part of homescreen layout) for the user corresponding to the provided ID.
|
||||
func (jf *Jellyfin) GetDisplayPreferences(userID string) (map[string]interface{}, int, error) {
|
||||
url := fmt.Sprintf("%s/DisplayPreferences/usersettings?userId=%s&client=emby", jf.Server, userID)
|
||||
data, status, err := jf.get(url, nil)
|
||||
if err != nil || !(status == 204 || status == 200) {
|
||||
return nil, status, err
|
||||
}
|
||||
var displayprefs map[string]interface{}
|
||||
err = json.Unmarshal([]byte(data), &displayprefs)
|
||||
if err != nil {
|
||||
return nil, status, err
|
||||
}
|
||||
return displayprefs, status, nil
|
||||
}
|
||||
|
||||
// SetDisplayPreferences sets the displayPreferences (part of homescreen layout) for the user corresponding to the provided ID.
|
||||
func (jf *Jellyfin) SetDisplayPreferences(userID string, displayprefs map[string]interface{}) (int, error) {
|
||||
url := fmt.Sprintf("%s/DisplayPreferences/usersettings?userId=%s&client=emby", jf.Server, userID)
|
||||
_, status, err := jf.post(url, displayprefs, false)
|
||||
if err != nil || !(status == 204 || status == 200) {
|
||||
return status, err
|
||||
}
|
||||
return status, nil
|
||||
}
|
||||
221
lang.go
Normal file
@@ -0,0 +1,221 @@
|
||||
package main
|
||||
|
||||
type langMeta struct {
|
||||
Name string `json:"name"`
|
||||
// Language to fall back on if strings are missing. Defaults to en-us.
|
||||
Fallback string `json:"fallback,omitempty"`
|
||||
}
|
||||
|
||||
type quantityString struct {
|
||||
Singular string `json:"singular"`
|
||||
Plural string `json:"plural"`
|
||||
}
|
||||
|
||||
type adminLangs map[string]adminLang
|
||||
|
||||
func (ls *adminLangs) getOptions() [][2]string {
|
||||
opts := make([][2]string, len(*ls))
|
||||
i := 0
|
||||
for key, lang := range *ls {
|
||||
opts[i] = [2]string{key, lang.Meta.Name}
|
||||
i++
|
||||
}
|
||||
return opts
|
||||
}
|
||||
|
||||
type commonLangs map[string]commonLang
|
||||
|
||||
type commonLang struct {
|
||||
Meta langMeta `json:"meta"`
|
||||
Strings langSection `json:"strings"`
|
||||
}
|
||||
|
||||
type adminLang struct {
|
||||
Meta langMeta `json:"meta"`
|
||||
Strings langSection `json:"strings"`
|
||||
Notifications langSection `json:"notifications"`
|
||||
QuantityStrings map[string]quantityString `json:"quantityStrings"`
|
||||
JSON string
|
||||
}
|
||||
|
||||
type formLangs map[string]formLang
|
||||
|
||||
func (ls *formLangs) getOptions() [][2]string {
|
||||
opts := make([][2]string, len(*ls))
|
||||
i := 0
|
||||
for key, lang := range *ls {
|
||||
opts[i] = [2]string{key, lang.Meta.Name}
|
||||
i++
|
||||
}
|
||||
return opts
|
||||
}
|
||||
|
||||
type formLang struct {
|
||||
Meta langMeta `json:"meta"`
|
||||
Strings langSection `json:"strings"`
|
||||
Notifications langSection `json:"notifications"`
|
||||
notificationsJSON string
|
||||
ValidationStrings map[string]quantityString `json:"validationStrings"`
|
||||
validationStringsJSON string
|
||||
}
|
||||
|
||||
type pwrLangs map[string]pwrLang
|
||||
|
||||
func (ls *pwrLangs) getOptions() [][2]string {
|
||||
opts := make([][2]string, len(*ls))
|
||||
i := 0
|
||||
for key, lang := range *ls {
|
||||
opts[i] = [2]string{key, lang.Meta.Name}
|
||||
i++
|
||||
}
|
||||
return opts
|
||||
}
|
||||
|
||||
type pwrLang struct {
|
||||
Meta langMeta `json:"meta"`
|
||||
Strings langSection `json:"strings"`
|
||||
}
|
||||
|
||||
type emailLangs map[string]emailLang
|
||||
|
||||
func (ls *emailLangs) getOptions() [][2]string {
|
||||
opts := make([][2]string, len(*ls))
|
||||
i := 0
|
||||
for key, lang := range *ls {
|
||||
opts[i] = [2]string{key, lang.Meta.Name}
|
||||
i++
|
||||
}
|
||||
return opts
|
||||
}
|
||||
|
||||
type emailLang struct {
|
||||
Meta langMeta `json:"meta"`
|
||||
Strings langSection `json:"strings"`
|
||||
UserCreated langSection `json:"userCreated"`
|
||||
InviteExpiry langSection `json:"inviteExpiry"`
|
||||
PasswordReset langSection `json:"passwordReset"`
|
||||
UserDeleted langSection `json:"userDeleted"`
|
||||
UserDisabled langSection `json:"userDisabled"`
|
||||
UserEnabled langSection `json:"userEnabled"`
|
||||
InviteEmail langSection `json:"inviteEmail"`
|
||||
WelcomeEmail langSection `json:"welcomeEmail"`
|
||||
EmailConfirmation langSection `json:"emailConfirmation"`
|
||||
UserExpired langSection `json:"userExpired"`
|
||||
}
|
||||
|
||||
type setupLangs map[string]setupLang
|
||||
|
||||
type setupLang struct {
|
||||
Meta langMeta `json:"meta"`
|
||||
Strings langSection `json:"strings"`
|
||||
StartPage langSection `json:"startPage"`
|
||||
EndPage langSection `json:"endPage"`
|
||||
General langSection `json:"general"`
|
||||
Updates langSection `json:"updates"`
|
||||
Language langSection `json:"language"`
|
||||
Login langSection `json:"login"`
|
||||
JellyfinEmby langSection `json:"jellyfinEmby"`
|
||||
Ombi langSection `json:"ombi"`
|
||||
Email langSection `json:"email"`
|
||||
Notifications langSection `json:"notifications"`
|
||||
WelcomeEmails langSection `json:"welcomeEmails"`
|
||||
PasswordResets langSection `json:"passwordResets"`
|
||||
InviteEmails langSection `json:"inviteEmails"`
|
||||
PasswordValidation langSection `json:"passwordValidation"`
|
||||
HelpMessages langSection `json:"helpMessages"`
|
||||
JSON string
|
||||
}
|
||||
|
||||
func (ls *setupLangs) getOptions() [][2]string {
|
||||
opts := make([][2]string, len(*ls))
|
||||
i := 0
|
||||
for key, lang := range *ls {
|
||||
opts[i] = [2]string{key, lang.Meta.Name}
|
||||
i++
|
||||
}
|
||||
return opts
|
||||
}
|
||||
|
||||
type telegramLangs map[string]telegramLang
|
||||
|
||||
type telegramLang struct {
|
||||
Meta langMeta `json:"meta"`
|
||||
Strings langSection `json:"strings"`
|
||||
}
|
||||
|
||||
func (ts *telegramLangs) getOptions() [][2]string {
|
||||
opts := make([][2]string, len(*ts))
|
||||
i := 0
|
||||
for key, lang := range *ts {
|
||||
opts[i] = [2]string{key, lang.Meta.Name}
|
||||
i++
|
||||
}
|
||||
return opts
|
||||
}
|
||||
|
||||
type langSection map[string]string
|
||||
type tmpl map[string]string
|
||||
|
||||
func templateString(text string, vals tmpl) string {
|
||||
start, previousEnd := -1, -1
|
||||
out := ""
|
||||
for i := range text {
|
||||
if text[i] == '{' {
|
||||
start = i
|
||||
continue
|
||||
}
|
||||
if start != -1 && text[i] == '}' {
|
||||
varName := text[start+1 : i]
|
||||
val, ok := vals[varName]
|
||||
if !ok {
|
||||
start = -1
|
||||
continue
|
||||
}
|
||||
out += text[previousEnd+1:start] + val
|
||||
previousEnd = i
|
||||
start = -1
|
||||
}
|
||||
}
|
||||
if previousEnd != len(text)-1 {
|
||||
out += text[previousEnd+1:]
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (el langSection) template(field string, vals tmpl) string {
|
||||
text := el.get(field)
|
||||
return templateString(text, vals)
|
||||
}
|
||||
|
||||
func (el langSection) format(field string, vals ...string) string {
|
||||
text := el.get(field)
|
||||
start, previous := -1, -3
|
||||
out := ""
|
||||
val := 0
|
||||
for i := range text {
|
||||
if i == len(text)-2 { // Check if there's even enough space for a {n}
|
||||
break
|
||||
}
|
||||
if text[i:i+3] == "{n}" {
|
||||
start = i
|
||||
out += text[previous+3:start] + vals[val]
|
||||
previous = start
|
||||
val++
|
||||
if val == len(vals) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if previous+2 != len(text)-1 {
|
||||
out += text[previous+3:]
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (el langSection) get(field string) string {
|
||||
t, ok := el[field]
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
return t
|
||||
}
|
||||
167
lang/admin/de-de.json
Normal file
@@ -0,0 +1,167 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Deutsch (DE)"
|
||||
},
|
||||
"strings": {
|
||||
"invites": "Invites",
|
||||
"accounts": "Konten",
|
||||
"settings": "Einstellungen",
|
||||
"inviteDays": "Tage",
|
||||
"inviteHours": "Stunden",
|
||||
"inviteMinutes": "Minuten",
|
||||
"inviteNumberOfUses": "Anzahl Verwendungen",
|
||||
"warning": "Warnung",
|
||||
"inviteInfiniteUsesWarning": "Invites mit unendlich vielen Verwendungen können missbräuchlich verwendet werden",
|
||||
"inviteSendToEmail": "Senden an",
|
||||
"login": "Anmelden",
|
||||
"logout": "Abmelden",
|
||||
"create": "Erstellen",
|
||||
"apply": "Anwenden",
|
||||
"delete": "Löschen",
|
||||
"name": "Name",
|
||||
"date": "Datum",
|
||||
"lastActiveTime": "Zuletzt aktiv",
|
||||
"from": "Von",
|
||||
"user": "Benutzer",
|
||||
"aboutProgram": "Über",
|
||||
"version": "Version",
|
||||
"commitNoun": "Commit",
|
||||
"newUser": "Neuer Benutzer",
|
||||
"profile": "Profil",
|
||||
"unknown": "Unbekannt",
|
||||
"modifySettings": "Einstellungen ändern",
|
||||
"modifySettingsDescription": "Wende Einstellungen von einem bestehenden Profil an, oder beziehe sie direkt von einem Benutzer.",
|
||||
"applyHomescreenLayout": "Startbildschirmlayout anwenden",
|
||||
"sendDeleteNotificationEmail": "Benachrichtigungs-E-Mail senden",
|
||||
"sendDeleteNotifiationExample": "Dein Konto wurde gelöscht.",
|
||||
"settingsRestartRequired": "Neustart erforderlich",
|
||||
"settingsRestartRequiredDescription": "Ein Neustart ist notwendig, um einige Einstellungen anzuwenden, die du geändert hast. Jetzt oder später neu starten?",
|
||||
"settingsApplyRestartLater": "Anwenden, später neu starten",
|
||||
"settingsApplyRestartNow": "Anwenden & neu starten",
|
||||
"settingsApplied": "Einstellungen angewendet.",
|
||||
"settingsRefreshPage": "Aktualisiere die Seite in ein paar Sekunden.",
|
||||
"settingsRequiredOrRestartMessage": "Hinweis: {n} zeigt ein erforderliches Feld an, {n} zeigt an, dass Änderungen einen Neustart erfordern.",
|
||||
"settingsSave": "Speichern",
|
||||
"ombiUserDefaults": "Ombi-Benutzerstandardeinstellungen",
|
||||
"ombiUserDefaultsDescription": "Erstelle einen Ombi-Benutzer und konfiguriere ihn, dann wähle ihn unten aus. Seine Einstellungen/Berechtigungen werden gespeichert und auf neue Ombi-Benutzer, erstellt von jfa-go, angewendet",
|
||||
"userProfiles": "Benutzerprofile",
|
||||
"userProfilesDescription": "Profile werden auf Benutzer angewendet, wenn sie ein Konto erstellen. Ein Profil beinhaltet Bibliothekszugriffsrechte und das Startbildschirmlayout.",
|
||||
"userProfilesIsDefault": "Standard",
|
||||
"userProfilesLibraries": "Bibliotheken",
|
||||
"addProfile": "Profil hinzufügen",
|
||||
"addProfileDescription": "Erstelle einen Jellyfin-Benutzer und konfiguriere ihn, dann wähle ihn unten aus. Wenn dieses Profil auf einen Invite angewendet ist, werden neue Benutzer mit den Einstellungen erstellt.",
|
||||
"addProfileNameOf": "Profilname",
|
||||
"addProfileStoreHomescreenLayout": "Startbildschirmlayout speichern",
|
||||
"inviteNoUsersCreated": "Noch keine!",
|
||||
"inviteUsersCreated": "Erstellte Benutzer",
|
||||
"inviteNoProfile": "Kein Profil",
|
||||
"inviteDateCreated": "Erstellt",
|
||||
"inviteRemainingUses": "Verbleibende Verwendungen",
|
||||
"inviteNoInvites": "Keine",
|
||||
"inviteExpiresInTime": "Läuft in {n} ab",
|
||||
"notifyEvent": "Benachrichtigen bei:",
|
||||
"notifyInviteExpiry": "Bei Ablauf",
|
||||
"notifyUserCreation": "Bei Benutzererstellung",
|
||||
"label": "Label",
|
||||
"settingsRestarting": "Neustart…",
|
||||
"settingsRestart": "Neustart",
|
||||
"variables": "Variablen",
|
||||
"preview": "Vorschau",
|
||||
"reset": "Zurücksetzen",
|
||||
"edit": "Bearbeiten",
|
||||
"customizeMessages": "E-Mails anpassen",
|
||||
"customizeMessagesDescription": "Wenn du jfa-go's E-Mail-Vorlagen nicht benutzen willst, kannst du deinen eigenen unter Verwendung von Markdown erstellen.",
|
||||
"announce": "Ankündigen",
|
||||
"subject": "E-Mail-Betreff",
|
||||
"message": "Nachricht",
|
||||
"markdownSupported": "Markdown wird unterstützt.",
|
||||
"advancedSettings": "Erweiterte Einstellungen",
|
||||
"search": "Suchen",
|
||||
"userExpiry": "Benutzer Ablaufdatum",
|
||||
"inviteDuration": "Invite Dauer",
|
||||
"enabled": "Aktiviert",
|
||||
"userExpiryDescription": "Eine bestimmte Zeit nach der Anmeldung wird jfa-go das Konto löschen/deaktivieren. Du kannst dieses Verhalten in den Einstellungen ändern.",
|
||||
"disabled": "Deaktiviert",
|
||||
"admin": "Admin",
|
||||
"download": "Herunterladen",
|
||||
"update": "Aktualisieren",
|
||||
"updates": "Aktualisierungen",
|
||||
"expiry": "Ablaufdatum",
|
||||
"extendExpiry": "Ablaufdatum verlängern"
|
||||
},
|
||||
"notifications": {
|
||||
"changedEmailAddress": "E-Mail-Adresse von {n} geändert.",
|
||||
"userCreated": "Benutzer {n} erstellt.",
|
||||
"createProfile": "Profil {n} erstellt.",
|
||||
"saveSettings": "Einstellungen wurden gespeichert",
|
||||
"setOmbiDefaults": "Ombi-Standardeinstellungen gespeichert.",
|
||||
"errorConnection": "Konnte keine Verbindung zu jfa-go herstellen.",
|
||||
"error401Unauthorized": "Unberechtigt. Versuch, die Seite zu aktualisieren.",
|
||||
"errorSettingsAppliedNoHomescreenLayout": "Einstellungen wurden angewendet, aber die Anwendung des Startbildschirmlayouts ist möglicherweise fehlgeschlagen.",
|
||||
"errorHomescreenAppliedNoSettings": "Startbildschirmlayout wurde angewendet, aber die Anwendung der Einstellungen ist möglicherweise fehlgeschlagen.",
|
||||
"errorSettingsFailed": "Anwendung ist fehlgeschlagen.",
|
||||
"errorLoginBlank": "Der Benutzername und/oder das Passwort wurden nicht ausgefüllt.",
|
||||
"errorUnknown": "Unbekannter Fehler.",
|
||||
"errorBlankFields": "Felder wurden nicht ausgefüllt",
|
||||
"errorDeleteProfile": "Fehler beim Löschen des Profils {n}",
|
||||
"errorLoadProfiles": "Fehler beim Laden der Profile.",
|
||||
"errorCreateProfile": "Fehler beim Erstellen des Profils {n}",
|
||||
"errorSetDefaultProfile": "Fehler beim Setzen des Standardprofils.",
|
||||
"errorLoadUsers": "Fehler beim Laden der Benutzer.",
|
||||
"errorSaveSettings": "Einstellungen konnten nicht gespeichert werden.",
|
||||
"errorLoadSettings": "Fehler beim Laden der Einstellungen.",
|
||||
"errorSetOmbiDefaults": "Fehler beim Speichern der Ombi-Standardeinstellungen.",
|
||||
"errorLoadOmbiUsers": "Fehler beim Laden der Ombi-Benutzer.",
|
||||
"errorChangedEmailAddress": "E-Mail-Adresse von {n} konnte nicht geändert werden.",
|
||||
"errorFailureCheckLogs": "Fehlgeschlagen (überprüfe die Konsole/Logs)",
|
||||
"errorPartialFailureCheckLogs": "Teilweiser Fehlschlag (überprüfe die Konsole/Logs)",
|
||||
"errorUserCreated": "Fehler beim Erstellen des Benutzers {n}.",
|
||||
"errorSendWelcomeEmail": "Fehler beim Senden der Willkommens-E-Mail (überprüfe die Konsole/Logs)",
|
||||
"saveEmail": "E-Mail gespeichert.",
|
||||
"errorSaveEmail": "Fehler beim Speichern der E-Mail.",
|
||||
"sentAnnouncement": "Ankündigung gesendet.",
|
||||
"updateApplied": "Aktualisierung angewendet, bitte neu starten.",
|
||||
"errorApplyUpdate": "Fehler beim Anwenden der Aktualisierung, versuche es manuell.",
|
||||
"errorCheckUpdate": "Fehler beim Suchen nach Aktualisierungen.",
|
||||
"updateAvailable": "Eine neue Aktualisierung ist verfügbar, überprüfe die Einstellungen.",
|
||||
"noUpdatesAvailable": "Keinen neuen Aktualisierungen verfügbar."
|
||||
},
|
||||
"quantityStrings": {
|
||||
"modifySettingsFor": {
|
||||
"singular": "Einstellungen für {n} Benutzer ändern",
|
||||
"plural": "Einstellungen für {n} Benutzer ändern"
|
||||
},
|
||||
"deleteNUsers": {
|
||||
"singular": "{n} Benutzer löschen",
|
||||
"plural": "{n} Benutzer löschen"
|
||||
},
|
||||
"addUser": {
|
||||
"singular": "Benutzer hinzufügen",
|
||||
"plural": "Benutzer hinzufügen"
|
||||
},
|
||||
"deleteUser": {
|
||||
"singular": "Benutzer löschen",
|
||||
"plural": "Benutzer löschen"
|
||||
},
|
||||
"deletedUser": {
|
||||
"singular": "{n} Benutzer gelöscht.",
|
||||
"plural": "{n} Benutzer gelöscht."
|
||||
},
|
||||
"appliedSettings": {
|
||||
"singular": "Einstellungen auf {n} Benutzer angewendet.",
|
||||
"plural": "Einstellungen auf {n} Benutzer angewendet."
|
||||
},
|
||||
"announceTo": {
|
||||
"singular": "{n} Benutzer mitteilen",
|
||||
"plural": "{n} Benutzern mitteilen"
|
||||
},
|
||||
"extendExpiry": {
|
||||
"singular": "Ablaufdatum für {n} Benutzer verlängern",
|
||||
"plural": "Ablaufdatum für {n} Benutzer verlängern"
|
||||
},
|
||||
"extendedExpiry": {
|
||||
"singular": "Ablaufdatum für {n} Benutzer verlängern.",
|
||||
"plural": "Ablaufdatum für {n} Benutzer verlängern."
|
||||
}
|
||||
}
|
||||
}
|
||||
186
lang/admin/el-gr.json
Normal file
@@ -0,0 +1,186 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Ελληνικά (GR)"
|
||||
},
|
||||
"strings": {
|
||||
"invites": "Προσκλήσεις",
|
||||
"accounts": "Λογαριασμοί",
|
||||
"settings": "Ρυθμίσεις",
|
||||
"inviteDays": "Ημέρες",
|
||||
"inviteHours": "Ώρες",
|
||||
"inviteMinutes": "Λεπτά",
|
||||
"inviteNumberOfUses": "Αριθμός χρήσεων",
|
||||
"warning": "Προσοχή",
|
||||
"inviteInfiniteUsesWarning": "μπορεί να γίνει κατάχρηση των προσκλήσεων με άπειρες χρήσεις",
|
||||
"inviteSendToEmail": "Αποστολή σε",
|
||||
"login": "Σύνδεση",
|
||||
"logout": "Αποσύνδεση",
|
||||
"create": "Δημιουργία",
|
||||
"apply": "Εφαρμογή",
|
||||
"delete": "Διαγραφή",
|
||||
"name": "Όνομα",
|
||||
"date": "Ημερομηνία",
|
||||
"lastActiveTime": "Τελευταία Ενεργός",
|
||||
"from": "Απο",
|
||||
"user": "Χρήστης",
|
||||
"aboutProgram": "Σχετικά",
|
||||
"version": "Έκδοση",
|
||||
"commitNoun": "Καταχώρηση",
|
||||
"newUser": "Νέος Χρήστης",
|
||||
"profile": "Προφίλ",
|
||||
"unknown": "Άγνωστο",
|
||||
"label": "Ετικέτα",
|
||||
"modifySettings": "Επεξεργασία Ρυθμίσεων",
|
||||
"modifySettingsDescription": "Εφαρμογή ρυθμίσεων απο υπάρχον προφίλ ή απευθείας απο χρήστη.",
|
||||
"applyHomescreenLayout": "Εφαρμογή δομής αρχικής οθόνης",
|
||||
"sendDeleteNotificationEmail": "Αποστολή ενημερωτικού email",
|
||||
"sendDeleteNotifiationExample": "Ο λογαριασμός σας έχει διαγραφεί.",
|
||||
"settingsRestart": "Επανεκίνηση",
|
||||
"settingsRestarting": "Επανεκινεί…",
|
||||
"settingsRestartRequired": "Απαιτείται επανεκκίνηση",
|
||||
"settingsRestartRequiredDescription": "Απαιτείται επανεκκίνηση για να εφαρμοστούν κάποιες απο τις ρυθμίσεις που αλλάξατε. Επανεκκίνηση τώρα ή αργότερα?",
|
||||
"settingsApplyRestartLater": "Εφαρμογή, επανεκκίνηση αργότερα",
|
||||
"settingsApplyRestartNow": "Εφαρμογή και επανεκκίνηση",
|
||||
"settingsApplied": "Οι ρυθμίσεις εφαρμόστηκαν.",
|
||||
"settingsRefreshPage": "Επαναφορτόστε την σελίδα σε μερικά δεύτερα.",
|
||||
"settingsRequiredOrRestartMessage": "Σημείωση: {n} δηλώνει υποχρεωτικό πεδίο, {n} δηλώνει αλλαγές που απαιτούν επανεκκίνηση.",
|
||||
"settingsSave": "Αποθήκευση",
|
||||
"ombiUserDefaults": "Προεπιλογές χρήστη Ombi",
|
||||
"ombiUserDefaultsDescription": "Δημιουργήστε έναν χρήστη Ombi και ρυθμίστε τον, μετά επιλέξτε τον απο κάτω. Οι ρυθμίσεις/άδειες θα αποθηκευτούν και εφαρμοστούν σε νέους χρήστες Ombi που έχουν δημιουργηθεί απο το jfa-go",
|
||||
"userProfiles": "Προφιλ Χρήστη",
|
||||
"userProfilesDescription": "Τα προφίλ εφαρμόζονται στους χρήστες όταν δημιουργούν λογαριασμό. Το προφίλ περιέχει δικαιώματα στις βιβλιοθήκες και δομή αρχικής οθόνης.",
|
||||
"userProfilesIsDefault": "Προκαθορισμένα",
|
||||
"userProfilesLibraries": "Βιβλιοθήκες",
|
||||
"addProfile": "Προσθήκη Προφίλ",
|
||||
"addProfileDescription": "Δημιουργήστε χρήστη Jellyfin και ρυθμίστε τον, μετά επιλέξτε τον παρακάτω. Όταν αυτό το προφίλ επιλέγεται σε μία πρόσκληση, τότε οι νέοι χρήστες θα δημιουργηθούν με αυτές τις ρυθμίσεις.",
|
||||
"addProfileNameOf": "Όνομα Προφίλ",
|
||||
"addProfileStoreHomescreenLayout": "Αποθήκευση αρχικής οθόνης",
|
||||
"inviteNoUsersCreated": "Τίποτα ακόμα!",
|
||||
"inviteUsersCreated": "Δημιουργηθέντες χρήστες",
|
||||
"inviteNoProfile": "Κανένα Προφίλ",
|
||||
"inviteDateCreated": "Δημιουργηθέντα",
|
||||
"inviteRemainingUses": "Εναπομείναντες χρήσεις",
|
||||
"inviteNoInvites": "Καμία",
|
||||
"inviteExpiresInTime": "Λήγει σε {n}",
|
||||
"notifyEvent": "Ενημέρωση όταν:",
|
||||
"notifyInviteExpiry": "Στην λήξη",
|
||||
"notifyUserCreation": "Στην δημιουργία χρήστη",
|
||||
"variables": "Μεταβλητές",
|
||||
"preview": "Προεπισκόπηση",
|
||||
"reset": "Επαναφορά",
|
||||
"edit": "Επεξεργασία",
|
||||
"customizeMessages": "Παραμετροποίηση Emails",
|
||||
"advancedSettings": "Προχωρημένες Ρυθμίσεις",
|
||||
"customizeMessagesDescription": "Αν δεν θέλετε να ζρησιμοποιήσετε τα πρότυπα email του jfa-go, μπορείτε να δημιουργήσετε τα δικά σας με χρήση Markdown.",
|
||||
"updates": "Ενημερώσεις",
|
||||
"update": "Ενημέρωση",
|
||||
"download": "Λήψη",
|
||||
"search": "Αναζήτηση",
|
||||
"inviteDuration": "Διάρκεια Πρόσκλησης",
|
||||
"enabled": "Ενεργοποιημένο",
|
||||
"disabled": "Απενεργοποιημένο",
|
||||
"admin": "Διαχειριστής",
|
||||
"expiry": "Λήξη",
|
||||
"userExpiry": "Λήξη Χρήστη",
|
||||
"userExpiryDescription": "Μετά απο ένα καθορισμένο χρόνο μετά απο κάθε εγγραφή, το jfa-go θα διαγράφει/απενεργοποιεί τον λογαριασμό. Μπορείτε να αλλάξετε αυτή την συμπεριφορά στις ρυθμίσεις.",
|
||||
"announce": "Ανακοίνωση",
|
||||
"subject": "Θέμα Email",
|
||||
"message": "Μήνυμα",
|
||||
"extendExpiry": "Παράταση λήξης",
|
||||
"markdownSupported": "Το Markdown υποστυρίζεται.",
|
||||
"reEnable": "Επανα-ενεργοποίηση",
|
||||
"disable": "Απενεργοποίηση",
|
||||
"inviteMonths": "Μήνες"
|
||||
},
|
||||
"notifications": {
|
||||
"changedEmailAddress": "Αλλαγή {n} διεύθυνσεων email.",
|
||||
"userCreated": "Δημιουργήθηκε ο {n} χρήστης.",
|
||||
"createProfile": "Δημιουργήθηκε το {n} προφίλ.",
|
||||
"saveSettings": "Οι ρυθμίσεις αποθηκεύτηκαν",
|
||||
"setOmbiDefaults": "Αποθηκεύτηκαν οι προκαθορισμένες ρυθμίσεις του ombi.",
|
||||
"errorConnection": "Δεν μπόρεσε να συνδεθεί με το jfa-go.",
|
||||
"error401Unauthorized": "Ανεξουσιοδότητος. Προσπαθήστε να κάνετε επαναφόρτωση την σελίδα.",
|
||||
"errorSettingsAppliedNoHomescreenLayout": "Οι ρυθμίσεις αποθηκεύτηκαν, αλλά η καταχώρηση δομής αρχικής οθόνης ίσως απέτυχε.",
|
||||
"errorHomescreenAppliedNoSettings": "Η δομή αρχικής οθόνης εφαρμόστηκε, αλλά οι ρυθμίσεις ίσως απέτυχαν.",
|
||||
"errorSettingsFailed": "Η εφαρμογή απέτυχε.",
|
||||
"errorLoginBlank": "Το όνομα χρήστη και/ή ο κωδικός ήταν κενά.",
|
||||
"errorUnknown": "Άγνωστο σφάλμα.",
|
||||
"errorBlankFields": "Τα πεφία ήταν κενά",
|
||||
"errorDeleteProfile": "Αποτυχία διαγραφής του προφίλ {n}",
|
||||
"errorLoadProfiles": "Αποτυχία φόρτωσης των προφίλ.",
|
||||
"errorCreateProfile": "Αποτυχία δημιουργίας του προφίλ {n}",
|
||||
"errorSetDefaultProfile": "Αποτυχία ορισμού του προκαθορισμένου προφίλ.",
|
||||
"errorLoadUsers": "Αποτυχία φόρτωσης χρηστών.",
|
||||
"errorSaveSettings": "Αποτυχία αποθήκευσης ρυθμίσεων.",
|
||||
"errorLoadSettings": "Αποτυχία φόρτωσης ρυθμίσεων.",
|
||||
"errorSetOmbiDefaults": "Αποτυχία αποθήκευσης προκαθορισμένων ρυθμίσεων για το Ombi.",
|
||||
"errorLoadOmbiUsers": "Αποτυχία φόρτωσης χρηστών Ombi.",
|
||||
"errorChangedEmailAddress": "Αποτυχία αλλαγής email του {n}.",
|
||||
"errorFailureCheckLogs": "Αποτυχία (ελέγξτε κονσόλα/καταγραφές)",
|
||||
"errorPartialFailureCheckLogs": "Μερική αποτυχία (ελέγξτε κονσόλα/καταγραφές)",
|
||||
"errorUserCreated": "Αποτυχία δημιουργίας του χρήστη {n}.",
|
||||
"errorSendWelcomeEmail": "Αποτυχία αποστολής email καλωσορίσματος (ελέγξτε κονσόλα/καταγραφές)",
|
||||
"saveEmail": "Το email αποθηκεύτηκε.",
|
||||
"sentAnnouncement": "Ανακοίνωση εστάλη.",
|
||||
"updateApplied": "Η ενημέρωση εφαρμόστηκε, παρακαλώ επανεκκινήστε.",
|
||||
"errorSaveEmail": "Αποτυχία αποθήκευσης του email.",
|
||||
"errorApplyUpdate": "Αποτυχία εγκατάστασης ενημέρωσης, προσπαθήστε χειροκίνητα.",
|
||||
"errorCheckUpdate": "Αποτυχία ελέγχου για ενημερώσεις.",
|
||||
"updateAvailable": "Μια νέα ενημέρωση είναι διαθέσιμη, ελέγξτε τις ρυθμίσεις.",
|
||||
"noUpdatesAvailable": "Δεν υπάρχουν διαθέσιμες ενημερώσεις."
|
||||
},
|
||||
"quantityStrings": {
|
||||
"modifySettingsFor": {
|
||||
"singular": "Επεξεργασία Ρυθμίσεων για {n} χρήστη",
|
||||
"plural": "Επεξεργασία Ρυθμίσεων για {n} χρήστες"
|
||||
},
|
||||
"deleteNUsers": {
|
||||
"singular": "Διαγραφή {n} χρήστη",
|
||||
"plural": "Διαγραφή {n} χρηστών"
|
||||
},
|
||||
"addUser": {
|
||||
"singular": "Προσθήκη χρήστη",
|
||||
"plural": "Προσθήκη χρηστών"
|
||||
},
|
||||
"deleteUser": {
|
||||
"singular": "Διαγραφή Χρήστη",
|
||||
"plural": "Διαγραφή Χρηστών"
|
||||
},
|
||||
"deletedUser": {
|
||||
"singular": "Διαγράφη {n} χρήστη.",
|
||||
"plural": "Διαγράφησαν {n} χρήστες."
|
||||
},
|
||||
"appliedSettings": {
|
||||
"singular": "Εφαρμογή ρυθμίσεων σε {n} χρήστη.",
|
||||
"plural": "Εφαρμογή ρυθμίσεων σε {n} χρήστες."
|
||||
},
|
||||
"announceTo": {
|
||||
"singular": "Ανακοίνωση σε {n} χρήστη",
|
||||
"plural": "Ανακοίνωση σε {n} χρήστες"
|
||||
},
|
||||
"extendExpiry": {
|
||||
"plural": "Επέκταση λήξης σε {n} χρήστες",
|
||||
"singular": "Επέκταση λήξης σε {n} χρήστη"
|
||||
},
|
||||
"extendedExpiry": {
|
||||
"singular": "Εκτεταμένη λήξη για {n} χρήστη.",
|
||||
"plural": "Εκτεταμένη λήξη για {n} χρήστες."
|
||||
},
|
||||
"disableUsers": {
|
||||
"singular": "Απενεργοποίηση {n} χρήστη",
|
||||
"plural": "Απενεργοποίηση {n} χρηστών"
|
||||
},
|
||||
"reEnableUsers": {
|
||||
"singular": "Εκ νέου ενεργοποίηση {n} χρήστη",
|
||||
"plural": "Εκ νέου ενεργοποίηση {n} χρηστών"
|
||||
},
|
||||
"disabledUser": {
|
||||
"singular": "Απενεργοποιήθηκε {n} χρήστης.",
|
||||
"plural": "Απενεργοποιήθηκαν {n} χρήστες."
|
||||
},
|
||||
"enabledUser": {
|
||||
"singular": "Εργοποιήθηκε {n} χρήστης.",
|
||||
"plural": "Εργοποιήθηκαν {n} χρήστες."
|
||||
}
|
||||
}
|
||||
}
|
||||
5
lang/admin/en-gb.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "English (GB)"
|
||||
}
|
||||
}
|
||||
192
lang/admin/en-us.json
Normal file
@@ -0,0 +1,192 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "English (US)"
|
||||
},
|
||||
"strings": {
|
||||
"invites": "Invites",
|
||||
"accounts": "Accounts",
|
||||
"settings": "Settings",
|
||||
"inviteMonths": "Months",
|
||||
"inviteDays": "Days",
|
||||
"inviteHours": "Hours",
|
||||
"inviteMinutes": "Minutes",
|
||||
"inviteNumberOfUses": "Number of uses",
|
||||
"inviteDuration": "Invite Duration",
|
||||
"warning": "Warning",
|
||||
"inviteInfiniteUsesWarning": "invites with infinite uses can be used abusively",
|
||||
"inviteSendToEmail": "Send to",
|
||||
"login": "Login",
|
||||
"logout": "Logout",
|
||||
"create": "Create",
|
||||
"apply": "Apply",
|
||||
"delete": "Delete",
|
||||
"name": "Name",
|
||||
"date": "Date",
|
||||
"enabled": "Enabled",
|
||||
"disabled": "Disabled",
|
||||
"reEnable": "Re-enable",
|
||||
"disable": "Disable",
|
||||
"admin": "Admin",
|
||||
"updates": "Updates",
|
||||
"update": "Update",
|
||||
"download": "Download",
|
||||
"search": "Search",
|
||||
"advancedSettings": "Advanced Settings",
|
||||
"lastActiveTime": "Last Active",
|
||||
"from": "From",
|
||||
"user": "User",
|
||||
"expiry": "Expiry",
|
||||
"userExpiry": "User Expiry",
|
||||
"userExpiryDescription": "A specified amount of time after each signup, jfa-go will delete/disable the account. You can change this behaviour in settings.",
|
||||
"aboutProgram": "About",
|
||||
"version": "Version",
|
||||
"commitNoun": "Commit",
|
||||
"newUser": "New User",
|
||||
"profile": "Profile",
|
||||
"unknown": "Unknown",
|
||||
"label": "Label",
|
||||
"announce": "Announce",
|
||||
"subject": "Subject",
|
||||
"message": "Message",
|
||||
"variables": "Variables",
|
||||
"conditionals": "Conditionals",
|
||||
"preview": "Preview",
|
||||
"reset": "Reset",
|
||||
"edit": "Edit",
|
||||
"donate": "Donate",
|
||||
"contactThrough": "Contact through:",
|
||||
"extendExpiry": "Extend expiry",
|
||||
"customizeMessages": "Customize Messages",
|
||||
"customizeMessagesDescription": "If you don't want to use jfa-go's message templates, you can create your own using Markdown.",
|
||||
"markdownSupported": "Markdown is supported.",
|
||||
"modifySettings": "Modify Settings",
|
||||
"modifySettingsDescription": "Apply settings from an existing profile, or source them directly from a user.",
|
||||
"applyHomescreenLayout": "Apply homescreen layout",
|
||||
"sendDeleteNotificationEmail": "Send notification message",
|
||||
"sendDeleteNotifiationExample": "Your account has been deleted.",
|
||||
"settingsRestart": "Restart",
|
||||
"settingsRestarting": "Restarting…",
|
||||
"settingsRestartRequired": "Restart needed",
|
||||
"settingsRestartRequiredDescription": "A restart is necessary to apply some settings you changed. Restart now or later?",
|
||||
"settingsApplyRestartLater": "Apply, restart later",
|
||||
"settingsApplyRestartNow": "Apply & restart",
|
||||
"settingsApplied": "Settings applied.",
|
||||
"settingsRefreshPage": "Refresh the page in a few seconds.",
|
||||
"settingsRequiredOrRestartMessage": "Note: {n} indicates a required field, {n} indicates changes require a restart.",
|
||||
"settingsSave": "Save",
|
||||
"ombiUserDefaults": "Ombi user defaults",
|
||||
"ombiUserDefaultsDescription": "Create an Ombi user and configure it, then select it below. It's settings/permissions will be stored and applied to new Ombi users created by jfa-go",
|
||||
"userProfiles": "User Profiles",
|
||||
"userProfilesDescription": "Profiles are applied to users when they create an account. A profile include library access rights and homescreen layout.",
|
||||
"userProfilesIsDefault": "Default",
|
||||
"userProfilesLibraries": "Libraries",
|
||||
"addProfile": "Add Profile",
|
||||
"addProfileDescription": "Create a Jellyfin user and configure it, then select it below. When this profile is applied to an invite, new users will be created with the settings.",
|
||||
"addProfileNameOf": "Profile Name",
|
||||
"addProfileStoreHomescreenLayout": "Store homescreen layout",
|
||||
"inviteNoUsersCreated": "None yet!",
|
||||
"inviteUsersCreated": "Created users",
|
||||
"inviteNoProfile": "No Profile",
|
||||
"inviteDateCreated": "Created",
|
||||
"inviteRemainingUses": "Remaining uses",
|
||||
"inviteNoInvites": "None",
|
||||
"inviteExpiresInTime": "Expires in {n}",
|
||||
"notifyEvent": "Notify on:",
|
||||
"notifyInviteExpiry": "On expiry",
|
||||
"notifyUserCreation": "On user creation",
|
||||
"sendPIN": "Ask the user to send the PIN below to the bot."
|
||||
},
|
||||
"notifications": {
|
||||
"changedEmailAddress": "Changed email address of {n}.",
|
||||
"userCreated": "User {n} created.",
|
||||
"createProfile": "Created profile {n}.",
|
||||
"saveSettings": "Settings were saved",
|
||||
"saveEmail": "Email saved.",
|
||||
"sentAnnouncement": "Announcement sent.",
|
||||
"setOmbiDefaults": "Stored ombi defaults.",
|
||||
"updateApplied": "Update applied, please restart.",
|
||||
"updateAppliedRefresh": "Update applied, please refresh.",
|
||||
"telegramVerified": "Telegram account verified.",
|
||||
"errorConnection": "Couldn't connect to jfa-go.",
|
||||
"error401Unauthorized": "Unauthorized. Try refreshing the page.",
|
||||
"errorSettingsAppliedNoHomescreenLayout": "Settings were applied, but applying homescreen layout may have failed.",
|
||||
"errorHomescreenAppliedNoSettings": "Homescreen layout was applied, but applying settings may have failed.",
|
||||
"errorSettingsFailed": "Application failed.",
|
||||
"errorLoginBlank": "The username and/or password were left blank.",
|
||||
"errorUnknown": "Unknown error.",
|
||||
"errorSaveEmail": "Failed to save email.",
|
||||
"errorBlankFields": "Fields were left blank",
|
||||
"errorDeleteProfile": "Failed to delete profile {n}",
|
||||
"errorLoadProfiles": "Failed to load profiles.",
|
||||
"errorCreateProfile": "Failed to create profile {n}",
|
||||
"errorSetDefaultProfile": "Failed to set default profile.",
|
||||
"errorLoadUsers": "Failed to load users.",
|
||||
"errorSaveSettings": "Couldn't save settings.",
|
||||
"errorLoadSettings": "Failed to load settings.",
|
||||
"errorSetOmbiDefaults": "Failed to store ombi defaults.",
|
||||
"errorLoadOmbiUsers": "Failed to load ombi users.",
|
||||
"errorChangedEmailAddress": "Couldn't change email address of {n}.",
|
||||
"errorFailureCheckLogs": "Failed (check console/logs)",
|
||||
"errorPartialFailureCheckLogs": "Partial failure (check console/logs)",
|
||||
"errorUserCreated": "Failed to create user {n}.",
|
||||
"errorSendWelcomeEmail": "Failed to send welcome message (check console/logs)",
|
||||
"errorApplyUpdate": "Failed to apply update, try manually.",
|
||||
"errorCheckUpdate": "Failed to check for update.",
|
||||
"updateAvailable": "A new update is available, check settings.",
|
||||
"noUpdatesAvailable": "No new updates available."
|
||||
},
|
||||
"quantityStrings": {
|
||||
"modifySettingsFor": {
|
||||
"singular": "Modify Settings for {n} user",
|
||||
"plural": "Modify Settings for {n} users"
|
||||
},
|
||||
"deleteNUsers": {
|
||||
"singular": "Delete {n} user",
|
||||
"plural": "Delete {n} users"
|
||||
},
|
||||
"disableUsers": {
|
||||
"singular": "Disable {n} user",
|
||||
"plural": "Disable {n} users"
|
||||
},
|
||||
"reEnableUsers": {
|
||||
"singular": "Re-enable {n} user",
|
||||
"plural": "Re-enable {n} users"
|
||||
},
|
||||
"addUser": {
|
||||
"singular": "Add user",
|
||||
"plural": "Add users"
|
||||
},
|
||||
"deleteUser": {
|
||||
"singular": "Delete User",
|
||||
"plural": "Delete Users"
|
||||
},
|
||||
"deletedUser": {
|
||||
"singular": "Deleted {n} user.",
|
||||
"plural": "Deleted {n} users."
|
||||
},
|
||||
"disabledUser": {
|
||||
"singular": "Disabled {n} user.",
|
||||
"plural": "Disabled {n} users."
|
||||
},
|
||||
"enabledUser": {
|
||||
"singular": "Enabled {n} user.",
|
||||
"plural": "Enabled {n} users."
|
||||
},
|
||||
"announceTo": {
|
||||
"singular": "Announce to {n} user",
|
||||
"plural": "Announce to {n} users"
|
||||
},
|
||||
"appliedSettings": {
|
||||
"singular": "Applied settings to {n} user.",
|
||||
"plural": "Applied settings to {n} users."
|
||||
},
|
||||
"extendExpiry": {
|
||||
"singular": "Extend expiry for {n} user",
|
||||
"plural": "Extend expiry for {n} users"
|
||||
},
|
||||
"extendedExpiry": {
|
||||
"singular": "Extended expiry for {n} user.",
|
||||
"plural": "Extended expiry for {n} users."
|
||||
}
|
||||
}
|
||||
}
|
||||
187
lang/admin/es-es.json
Normal file
@@ -0,0 +1,187 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Español(ES)"
|
||||
},
|
||||
"strings": {
|
||||
"invites": "Invitaciones",
|
||||
"accounts": "Cuentas",
|
||||
"settings": "Ajustes",
|
||||
"inviteMonths": "Meses",
|
||||
"inviteDays": "Días",
|
||||
"inviteHours": "Horas",
|
||||
"inviteMinutes": "Minutos",
|
||||
"inviteNumberOfUses": "Números de usos",
|
||||
"inviteDuration": "Duración de invitación",
|
||||
"warning": "Advertencia",
|
||||
"inviteInfiniteUsesWarning": "Las invitaciones con usos infinitos pueden usarse abusivamente",
|
||||
"inviteSendToEmail": "Enviar a",
|
||||
"login": "Acceso",
|
||||
"logout": "Cerrar sesión",
|
||||
"create": "Cerrar sesión",
|
||||
"apply": "Aplicar",
|
||||
"delete": "Eliminar",
|
||||
"name": "Nombre",
|
||||
"date": "Fecha",
|
||||
"enabled": "Activado",
|
||||
"disabled": "Desactivado",
|
||||
"reEnable": "Reactivar",
|
||||
"disable": "Desactivar",
|
||||
"admin": "Administrador",
|
||||
"updates": "Actualizaciones",
|
||||
"update": "Actualizar",
|
||||
"download": "Descargar",
|
||||
"search": "Buscar",
|
||||
"advancedSettings": "Ajustes avanzados",
|
||||
"lastActiveTime": "Último activo",
|
||||
"from": "De",
|
||||
"user": "Usuario",
|
||||
"expiry": "Expiración",
|
||||
"userExpiry": "Caducidad del usuario",
|
||||
"userExpiryDescription": "Una cantidad específica de tiempo después de cada registro, jfa-go eliminará/deshabilitará la cuenta. Puede cambiar este comportamiento en la configuración.",
|
||||
"aboutProgram": "Acerca de",
|
||||
"version": "Versión",
|
||||
"commitNoun": "Cometer",
|
||||
"newUser": "Nuevo usuario",
|
||||
"profile": "Perfil",
|
||||
"unknown": "Desconocido",
|
||||
"label": "Etiqueta",
|
||||
"announce": "Anunciar",
|
||||
"subject": "Asunto del email",
|
||||
"message": "Mensaje",
|
||||
"variables": "Variables",
|
||||
"preview": "Previsualizar",
|
||||
"reset": "Reiniciar",
|
||||
"edit": "Editar",
|
||||
"extendExpiry": "Extender el vencimiento",
|
||||
"customizeMessages": "Personalizar emails",
|
||||
"customizeMessagesDescription": "Si no desea utilizar las plantillas de correo electrónico de jfa-go, puede crear las suyas propias con Markdown.",
|
||||
"markdownSupported": "Se admite Markdown.",
|
||||
"modifySettings": "Modificar configuración",
|
||||
"modifySettingsDescription": "Aplique la configuración de un perfil existente u obténgalos directamente de un usuario.",
|
||||
"applyHomescreenLayout": "Aplicar el diseño de la pantalla de inicio",
|
||||
"sendDeleteNotificationEmail": "Enviar notificación a correo",
|
||||
"sendDeleteNotifiationExample": "Tu cuenta ha sido eliminada.",
|
||||
"settingsRestart": "Reiniciar",
|
||||
"settingsRestarting": "Reiniciando…",
|
||||
"settingsRestartRequired": "Reinicio necesario",
|
||||
"settingsRestartRequiredDescription": "Es necesario reiniciar para aplicar algunas configuraciones que cambió. ¿Reiniciar ahora o más tarde?",
|
||||
"settingsApplyRestartLater": "Aplicar, reiniciar más tarde",
|
||||
"settingsApplyRestartNow": "Aplicar, reiniciar más tarde",
|
||||
"settingsApplied": "Se aplicó la configuración.",
|
||||
"settingsRefreshPage": "Actualiza la página en unos segundos.",
|
||||
"settingsRequiredOrRestartMessage": "Nota: {n} indica un campo obligatorio, {n} indica que los cambios requieren un reinicio.",
|
||||
"settingsSave": "Guardar",
|
||||
"ombiUserDefaults": "Valores predeterminados de usuario de Ombi",
|
||||
"ombiUserDefaultsDescription": "Cree un usuario Ombi y configúrelo, luego selecciónelo a continuación. Sus configuraciones / permisos se almacenarán y aplicarán a los nuevos usuarios de Ombi creados por jfa-go",
|
||||
"userProfiles": "Perfiles de usuario",
|
||||
"userProfilesDescription": "Los perfiles se aplican a los usuarios cuando crean una cuenta. Un perfil incluye los derechos de acceso a la biblioteca y el diseño de la pantalla de inicio.",
|
||||
"userProfilesIsDefault": "Defecto",
|
||||
"userProfilesLibraries": "Bibliotecas",
|
||||
"addProfile": "Agregar perfil",
|
||||
"addProfileDescription": "Cree un usuario de Jellyfin y configúrelo, luego selecciónelo a continuación. Cuando este perfil se aplica a una invitación, se crearán nuevos usuarios con la configuración.",
|
||||
"addProfileNameOf": "Nombre de perfil",
|
||||
"addProfileStoreHomescreenLayout": "Diseño de la pantalla de inicio de la tienda",
|
||||
"inviteNoUsersCreated": "¡Ninguno todavía!",
|
||||
"inviteUsersCreated": "Usuarios creados",
|
||||
"inviteNoProfile": "Sin perfil",
|
||||
"inviteDateCreated": "Creado",
|
||||
"inviteRemainingUses": "Usos restantes",
|
||||
"inviteNoInvites": "Ninguno",
|
||||
"inviteExpiresInTime": "Caduca en {n}",
|
||||
"notifyEvent": "Notificar en:",
|
||||
"notifyInviteExpiry": "Al vencimiento",
|
||||
"notifyUserCreation": "Sobre la creación de usuarios",
|
||||
"conditionals": "Condicionales"
|
||||
},
|
||||
"notifications": {
|
||||
"changedEmailAddress": "Se cambió la dirección de correo electrónico de {n}.",
|
||||
"userCreated": "Usuario {n} creado.",
|
||||
"createProfile": "Perfil creado {n}.",
|
||||
"saveSettings": "Se guardaron las configuraciones",
|
||||
"saveEmail": "Correo electrónico guardado.",
|
||||
"sentAnnouncement": "Anuncio enviado.",
|
||||
"setOmbiDefaults": "Valores predeterminados de ombi almacenados.",
|
||||
"updateApplied": "Actualización aplicada, por favor reinicie.",
|
||||
"errorConnection": "No se pudo conectar a jfa-go.",
|
||||
"error401Unauthorized": "No autorizado. Intente actualizar la página.",
|
||||
"errorSettingsAppliedNoHomescreenLayout": "Se aplicó la configuración, pero es posible que no se haya aplicado el diseño de la pantalla de inicio.",
|
||||
"errorHomescreenAppliedNoSettings": "Se aplicó el diseño de la pantalla de inicio, pero es posible que no se haya aplicado la configuración.",
|
||||
"errorSettingsFailed": "La aplicación falló.",
|
||||
"errorLoginBlank": "El nombre de usuario y/o la contraseña se dejaron en blanco.",
|
||||
"errorUnknown": "Error desconocido.",
|
||||
"errorSaveEmail": "No se pudo guardar el correo electrónico.",
|
||||
"errorBlankFields": "Los campos se dejaron en blanco",
|
||||
"errorDeleteProfile": "No se pudo borrar el perfil {n}",
|
||||
"errorLoadProfiles": "No se pudieron cargar los perfiles.",
|
||||
"errorCreateProfile": "No se pudo crear el perfil {n}",
|
||||
"errorSetDefaultProfile": "No se pudo establecer el perfil predeterminado.",
|
||||
"errorLoadUsers": "No se pudieron cargar los usuarios.",
|
||||
"errorSaveSettings": "No se pudo guardar la configuración.",
|
||||
"errorLoadSettings": "No se pudo cargar la configuración.",
|
||||
"errorSetOmbiDefaults": "No se pudieron almacenar los valores predeterminados de ombi.",
|
||||
"errorLoadOmbiUsers": "No se pudieron cargar los usuarios de ombi.",
|
||||
"errorChangedEmailAddress": "No se pudo cambiar la dirección de correo electrónico de {n}.",
|
||||
"errorFailureCheckLogs": "Fallido (ver consola / registros)",
|
||||
"errorPartialFailureCheckLogs": "Fallo parcial (ver consola / registros)",
|
||||
"errorUserCreated": "No se pudo crear el usuario {n}.",
|
||||
"errorSendWelcomeEmail": "No se pudo enviar el correo electrónico de bienvenida (verifique la consola / registros)",
|
||||
"errorApplyUpdate": "No se pudo aplicar la actualización, intente manualmente.",
|
||||
"errorCheckUpdate": "No se pudo comprobar la actualización.",
|
||||
"updateAvailable": "Hay una nueva actualización disponible, verifique la configuración.",
|
||||
"noUpdatesAvailable": "No hay nuevas actualizaciones disponibles."
|
||||
},
|
||||
"quantityStrings": {
|
||||
"modifySettingsFor": {
|
||||
"singular": "Modificar la configuración de {n} usuario",
|
||||
"plural": "Modificar la configuración de {n} usuarios"
|
||||
},
|
||||
"deleteNUsers": {
|
||||
"singular": "Eliminar {n} usuario",
|
||||
"plural": "Eliminar {n} usuarios"
|
||||
},
|
||||
"disableUsers": {
|
||||
"singular": "Deshabilitar {n} usuario",
|
||||
"plural": "Inhabilitar {n} usuarios"
|
||||
},
|
||||
"reEnableUsers": {
|
||||
"singular": "Reactivar {n} usuario",
|
||||
"plural": "Reactivar {n} usuarios"
|
||||
},
|
||||
"addUser": {
|
||||
"singular": "Agregar usuario",
|
||||
"plural": "Agregar usuarios"
|
||||
},
|
||||
"deleteUser": {
|
||||
"singular": "Borrar usuario",
|
||||
"plural": "Borrar usuarios"
|
||||
},
|
||||
"deletedUser": {
|
||||
"singular": "Usuario eliminado {n}.",
|
||||
"plural": "Usuarios eliminados {n}."
|
||||
},
|
||||
"disabledUser": {
|
||||
"singular": "Usuario deshabilitado {n}.",
|
||||
"plural": "Usuarios deshabilitados {n}."
|
||||
},
|
||||
"enabledUser": {
|
||||
"singular": "Usuario {n} habilitado.",
|
||||
"plural": "Usuarios {n} habilitados."
|
||||
},
|
||||
"announceTo": {
|
||||
"singular": "Anunciar al usuario {n}",
|
||||
"plural": "Anunciar a los usuarios {n}"
|
||||
},
|
||||
"appliedSettings": {
|
||||
"singular": "Se aplicó la configuración al usuario {n}.",
|
||||
"plural": "Se aplicó la configuración a los usuarios {n}."
|
||||
},
|
||||
"extendExpiry": {
|
||||
"singular": "Extender la expiración para el usuario {n}",
|
||||
"plural": "Extender la expiración para los usuarios {n}"
|
||||
},
|
||||
"extendedExpiry": {
|
||||
"singular": "Caducidad extendida para el usuario {n}.",
|
||||
"plural": "Caducidad extendida para los usuarios {n}."
|
||||
}
|
||||
}
|
||||
}
|
||||
158
lang/admin/fr-fr.json
Normal file
@@ -0,0 +1,158 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Français (FR)",
|
||||
"author": "https://github.com/Killianbe"
|
||||
},
|
||||
"strings": {
|
||||
"invites": "Invitations",
|
||||
"accounts": "Comptes",
|
||||
"settings": "Réglages",
|
||||
"inviteMonths": "Mois",
|
||||
"inviteDays": "Jours",
|
||||
"inviteHours": "Heures",
|
||||
"inviteMinutes": "Minutes",
|
||||
"inviteNumberOfUses": "Nombre d'utilisateurs",
|
||||
"warning": "Attention",
|
||||
"inviteInfiniteUsesWarning": "les invitations infinies peuvent être utilisées abusivement",
|
||||
"inviteSendToEmail": "Envoyer à",
|
||||
"login": "S'identifier",
|
||||
"logout": "Se déconnecter",
|
||||
"create": "Créer",
|
||||
"apply": "Appliquer",
|
||||
"delete": "Effacer",
|
||||
"name": "Nom",
|
||||
"date": "Date",
|
||||
"lastActiveTime": "Dernière activité",
|
||||
"from": "De",
|
||||
"user": "Utilisateur",
|
||||
"aboutProgram": "A propos",
|
||||
"version": "Version",
|
||||
"commitNoun": "Commettre",
|
||||
"newUser": "Nouvel utilisateur",
|
||||
"profile": "Profil",
|
||||
"unknown": "Inconnu",
|
||||
"modifySettings": "Modifier les paramètres",
|
||||
"modifySettingsDescription": "Appliquez les paramètres à partir d'un profil existant ou obtenez-les directement auprès d'un utilisateur.",
|
||||
"applyHomescreenLayout": "Appliquer la disposition de l'écran d'accueil",
|
||||
"sendDeleteNotificationEmail": "Envoyer un e-mail de notification",
|
||||
"sendDeleteNotifiationExample": "Votre compte a été supprimé.",
|
||||
"settingsRestartRequired": "Redémarrage nécessaire",
|
||||
"settingsRestartRequiredDescription": "Un redémarrage est nécessaire pour appliquer certains paramètres que vous avez modifiés. Redémarrer maintenant ou plus tard ?",
|
||||
"settingsApplyRestartLater": "Appliquer, redémarrer plus tard",
|
||||
"settingsApplyRestartNow": "Appliquer et redémarrer",
|
||||
"settingsApplied": "Paramètres appliqués.",
|
||||
"settingsRefreshPage": "Actualisez la page dans quelques secondes.",
|
||||
"settingsRequiredOrRestartMessage": "Remarque : {n} indique un champ obligatoire, {n} indique que les modifications nécessitent un redémarrage.",
|
||||
"settingsSave": "Sauver",
|
||||
"ombiUserDefaults": "Paramètres par défaut de l'utilisateur Ombi",
|
||||
"ombiUserDefaultsDescription": "Créez un utilisateur Ombi et configurez-le, puis sélectionnez-le ci-dessous. Ses paramètres/autorisations seront stockés et appliqués aux nouveaux utilisateurs Ombi créés par jfa-go",
|
||||
"userProfiles": "Profils d'utilisateurs",
|
||||
"userProfilesDescription": "Les profils sont appliqués aux utilisateurs lorsqu'ils créent un compte. Un profil inclut les droits d'accès à la bibliothèque et la disposition de l'écran d'accueil.",
|
||||
"userProfilesIsDefault": "Défaut",
|
||||
"userProfilesLibraries": "Bibliothèques",
|
||||
"addProfile": "Ajouter un profil",
|
||||
"addProfileDescription": "Créez un utilisateur Jellyfin et configurez-le, puis sélectionnez-le ci-dessous. Lorsque ce profil est appliqué à une invitation, les nouveaux utilisateurs seront créés avec ces paramètres.",
|
||||
"addProfileNameOf": "Nom de profil",
|
||||
"addProfileStoreHomescreenLayout": "Enregistrer la disposition de l'écran d'accueil",
|
||||
"inviteNoUsersCreated": "Aucun pour l'instant !",
|
||||
"inviteUsersCreated": "Utilisateurs créer",
|
||||
"inviteNoProfile": "Aucun profil",
|
||||
"inviteDateCreated": "Créer",
|
||||
"inviteRemainingUses": "Utilisations restantes",
|
||||
"inviteNoInvites": "Aucune",
|
||||
"inviteExpiresInTime": "Expires dans {n}",
|
||||
"notifyEvent": "Notifier sur :",
|
||||
"notifyInviteExpiry": "À l'expiration",
|
||||
"notifyUserCreation": "à la création de l'utilisateur",
|
||||
"label": "Etiquette",
|
||||
"settingsRestarting": "Redémarrage…",
|
||||
"settingsRestart": "Redémarrer",
|
||||
"announce": "Annoncer",
|
||||
"subject": "Sujet",
|
||||
"message": "Message",
|
||||
"markdownSupported": "Markdown est pris en charge.",
|
||||
"customizeMessagesDescription": "Si vous ne souhaitez pas utiliser les modèles d'e-mails de jfa-go, vous pouvez créer les vôtres à l'aide de Markdown.",
|
||||
"variables": "Variables",
|
||||
"preview": "Aperçu",
|
||||
"reset": "Réinitialiser",
|
||||
"edit": "Éditer",
|
||||
"customizeMessages": "Personnaliser les e-mails",
|
||||
"inviteDuration": "Durée de l'invitation",
|
||||
"enabled": "Activé",
|
||||
"disabled": "Désactivé",
|
||||
"reEnable": "Ré-activé",
|
||||
"disable": "Désactivé",
|
||||
"admin": "Administrateur",
|
||||
"expiry": "Expiration",
|
||||
"advancedSettings": "Paramètres avancés",
|
||||
"userExpiry": "Expiration de l'utilisateur",
|
||||
"updates": "Mises à jour",
|
||||
"update": "Mise à jour",
|
||||
"download": "Téléchargement",
|
||||
"search": "Recherche",
|
||||
"conditionals": "Conditions"
|
||||
},
|
||||
"notifications": {
|
||||
"changedEmailAddress": "Adresse e-mail modifiée de {n}.",
|
||||
"userCreated": "L'utilisateur {n} a été créé.",
|
||||
"createProfile": "Profil créé {n}.",
|
||||
"saveSettings": "Les paramètres ont été enregistrés",
|
||||
"setOmbiDefaults": "Valeurs par défaut de Ombi.",
|
||||
"errorConnection": "Impossible de se connecter à jfa-go.",
|
||||
"error401Unauthorized": "Non autorisé. Essayez d'actualiser la page.",
|
||||
"errorSettingsAppliedNoHomescreenLayout": "Les paramètres ont été appliqués, mais l'application de la disposition de l'écran d'accueil a peut-être échoué.",
|
||||
"errorHomescreenAppliedNoSettings": "La disposition de l'écran d'accueil a été appliquée, mais l'application des paramètres a peut-être échoué.",
|
||||
"errorSettingsFailed": "L'application a échoué.",
|
||||
"errorLoginBlank": "Le nom d'utilisateur et/ou le mot de passe sont vides.",
|
||||
"errorUnknown": "Erreur inconnue.",
|
||||
"errorBlankFields": "Les champs sont vides",
|
||||
"errorDeleteProfile": "Échec de la suppression du profil {n}",
|
||||
"errorLoadProfiles": "Échec du chargement des profils.",
|
||||
"errorCreateProfile": "Échec de la création du profil {n}",
|
||||
"errorSetDefaultProfile": "Échec de la définition du profil par défaut.",
|
||||
"errorLoadUsers": "Échec du chargement des utilisateurs.",
|
||||
"errorSaveSettings": "Impossible d'enregistrer les paramètres.",
|
||||
"errorLoadSettings": "Échec du chargement des paramètres.",
|
||||
"errorSetOmbiDefaults": "Impossible de stocker les valeurs par défaut d'Ombi.",
|
||||
"errorLoadOmbiUsers": "Échec du chargement des utilisateurs Ombi.",
|
||||
"errorChangedEmailAddress": "Impossible de modifier l'adresse e-mail de {n}.",
|
||||
"errorFailureCheckLogs": "Échec (vérifier la console / les journaux)",
|
||||
"errorPartialFailureCheckLogs": "Panne partielle (vérifier la console / les journaux)",
|
||||
"errorUserCreated": "Echec lors de la création de l'utilisateur {n}.",
|
||||
"errorSendWelcomeEmail": "Echec lors de l'envoi du mail de bienvenue (vérifier la console/les journaux)",
|
||||
"sentAnnouncement": "Annonce envoyée.",
|
||||
"saveEmail": "Email enregistré.",
|
||||
"errorSaveEmail": "Échec de l'enregistrement de l'e-mail.",
|
||||
"updateApplied": "Mise à jour appliquée, veuillez redémarrer."
|
||||
},
|
||||
"quantityStrings": {
|
||||
"modifySettingsFor": {
|
||||
"singular": "Modifier les paramètres pour {n} utilisateur",
|
||||
"plural": "Modifier les paramètres pour {n} utilisateurs"
|
||||
},
|
||||
"deleteNUsers": {
|
||||
"singular": "Supprimer {n} utilisateur",
|
||||
"plural": "Supprimer {n} utilisateurs"
|
||||
},
|
||||
"addUser": {
|
||||
"singular": "Ajouter un utilisateur",
|
||||
"plural": "Ajouter des utilisateurs"
|
||||
},
|
||||
"deleteUser": {
|
||||
"singular": "Supprimer l'utilisateur",
|
||||
"plural": "Supprimer les utilisateurs"
|
||||
},
|
||||
"deletedUser": {
|
||||
"singular": "Supprimer {n} utilisateur.",
|
||||
"plural": "Supprimer {n} utilisateurs."
|
||||
},
|
||||
"appliedSettings": {
|
||||
"singular": "Appliquer le paramètre {n} utilisteur.",
|
||||
"plural": "Appliquer les paramètres {n} utilisteurs."
|
||||
},
|
||||
"announceTo": {
|
||||
"singular": "Annonce à {n} utilisateur",
|
||||
"plural": "Annonce à {n} utilisateurs"
|
||||
}
|
||||
}
|
||||
}
|
||||
141
lang/admin/id-id.json
Normal file
@@ -0,0 +1,141 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Bahasa Indonesia (ID)"
|
||||
},
|
||||
"strings": {
|
||||
"invites": "Undangan",
|
||||
"accounts": "Akun",
|
||||
"settings": "Pengaturan",
|
||||
"inviteDays": "Hari",
|
||||
"inviteHours": "Jam",
|
||||
"inviteMinutes": "Menit",
|
||||
"inviteNumberOfUses": "Jumlah penggunaan",
|
||||
"warning": "Peringatan",
|
||||
"inviteInfiniteUsesWarning": "Undangan dalam jumlah tak terbatas dapat disalahgunakan",
|
||||
"inviteSendToEmail": "Dikirim kepada",
|
||||
"login": "Masuk",
|
||||
"logout": "Keluar",
|
||||
"create": "Buat",
|
||||
"apply": "Terapkan",
|
||||
"delete": "Hapus",
|
||||
"name": "Nama",
|
||||
"date": "Tanggal",
|
||||
"lastActiveTime": "Terakhir Aktif",
|
||||
"from": "Dari",
|
||||
"user": "Pengguna",
|
||||
"aboutProgram": "Tentang",
|
||||
"version": "Versi",
|
||||
"commitNoun": "Commit",
|
||||
"newUser": "Pengguna Baru",
|
||||
"profile": "Profil",
|
||||
"unknown": "Tidak diketahui",
|
||||
"label": "Label",
|
||||
"modifySettings": "Ganti Pengaturan",
|
||||
"modifySettingsDescription": "Terapkan pengaturan dari profil yang ada, atau dapatkan langsung dari pengguna.",
|
||||
"applyHomescreenLayout": "Terapkan tata letak layar beranda",
|
||||
"sendDeleteNotificationEmail": "Kirim email notifikasi",
|
||||
"sendDeleteNotifiationExample": "Akun anda telah dihapus.",
|
||||
"settingsRestart": "Mulai ulang",
|
||||
"settingsRestarting": "Mengulang kembali…",
|
||||
"settingsRestartRequired": "Mulai ulang diperlukan",
|
||||
"settingsRestartRequiredDescription": "Mulai ulang diperlukan untuk menerapkan beberapa pengaturan yang Anda ubah. Mulai ulang sekarang atau nanti?",
|
||||
"settingsApplyRestartLater": "Terapkan, mulai ulang nanti",
|
||||
"settingsApplyRestartNow": "Terapkan & mulai ulang",
|
||||
"settingsApplied": "Pengaturan diterapkan.",
|
||||
"settingsRefreshPage": "Segarkan halaman dalam beberapa detik.",
|
||||
"settingsRequiredOrRestartMessage": "Catatan: {n} harus diisi, {n} mengindikasikan perubahan memerlukan mulai ulang.",
|
||||
"settingsSave": "Simpan",
|
||||
"ombiUserDefaults": "Default pengguna Ombi",
|
||||
"ombiUserDefaultsDescription": "Buat pengguna Ombi dan konfigurasikan, lalu pilih di bawah. Pengaturan / izinnya akan disimpan dan diterapkan ke pengguna Ombi baru yang dibuat oleh jfa-go",
|
||||
"userProfiles": "Profil Pengguna",
|
||||
"userProfilesDescription": "Profil diterapkan ke pengguna saat mereka membuat akun. Profil mencakup hak akses perpustakaan dan tata letak layar utama.",
|
||||
"userProfilesIsDefault": "Default",
|
||||
"userProfilesLibraries": "Pustaka",
|
||||
"addProfile": "Tambahkan Profil",
|
||||
"addProfileDescription": "Buat pengguna Jellyfin dan konfigurasikan, lalu pilih di bawah. Saat profil ini diterapkan ke undangan, pengguna baru akan dibuat dengan pengaturan seperti ini.",
|
||||
"addProfileNameOf": "Nama Profil",
|
||||
"addProfileStoreHomescreenLayout": "Simpan tata letak layar beranda",
|
||||
"inviteNoUsersCreated": "Belum ada!",
|
||||
"inviteUsersCreated": "Pengguna yang telah dibuat",
|
||||
"inviteNoProfile": "Tidak ada profil",
|
||||
"inviteDateCreated": "Dibuat",
|
||||
"inviteRemainingUses": "Penggunaan yang tersisa",
|
||||
"inviteNoInvites": "Tidak ada",
|
||||
"inviteExpiresInTime": "Kadaluarsa dalam {n}",
|
||||
"notifyEvent": "Beritahu pada:",
|
||||
"notifyInviteExpiry": "Saat kadaluarsa",
|
||||
"notifyUserCreation": "Saat pembuatan pengguna",
|
||||
"variables": "Variabel",
|
||||
"preview": "Pratinjau",
|
||||
"reset": "Setel ulang",
|
||||
"edit": "Edit",
|
||||
"customizeMessages": "Sesuaikan Email",
|
||||
"customizeMessagesDescription": "Jika Anda tidak ingin menggunakan templat email jfa-go, Anda dapat membuatnya sendiri menggunakan Markdown.",
|
||||
"announce": "Mengumumkan",
|
||||
"subject": "Subjek Email",
|
||||
"message": "Pesan",
|
||||
"markdownSupported": "Markdown didukung."
|
||||
},
|
||||
"notifications": {
|
||||
"changedEmailAddress": "Alamat email {n} diubah.",
|
||||
"userCreated": "Pengguna {n} dibuat.",
|
||||
"createProfile": "Membuat profil {n}.",
|
||||
"saveSettings": "Pengaturan telah disimpan",
|
||||
"setOmbiDefaults": "Default ombi tersimpan.",
|
||||
"errorConnection": "Tidak dapat terhubung ke jfa-go.",
|
||||
"error401Unauthorized": "Tidak ter-otorisasi. Coba segarkan halaman.",
|
||||
"errorSettingsAppliedNoHomescreenLayout": "Pengaturan telah diterapkan, tetapi menerapkan tata letak layar utama mungkin gagal.",
|
||||
"errorHomescreenAppliedNoSettings": "Tata letak layar beranda diterapkan, tetapi menerapkan pengaturan mungkin gagal.",
|
||||
"errorSettingsFailed": "Aplikasi gagal.",
|
||||
"errorLoginBlank": "Nama pengguna dan / atau sandi kosong.",
|
||||
"errorUnknown": "Kesalahan yang tidak diketahui.",
|
||||
"errorBlankFields": "Isian dibiarkan kosong",
|
||||
"errorDeleteProfile": "Gagal menghapus profil {n}",
|
||||
"errorLoadProfiles": "Gagal memuat profil.",
|
||||
"errorCreateProfile": "Gagal membuat profil {n}",
|
||||
"errorSetDefaultProfile": "Gagal menyetel profil default.",
|
||||
"errorLoadUsers": "Gagal memuat pengguna.",
|
||||
"errorSaveSettings": "Tidak dapat menyimpan pengaturan.",
|
||||
"errorLoadSettings": "Gagal memuat pengaturan.",
|
||||
"errorSetOmbiDefaults": "Gagal menyimpan default ombi.",
|
||||
"errorLoadOmbiUsers": "Gagal memuat pengguna ombi.",
|
||||
"errorChangedEmailAddress": "Tidak dapat mengubah alamat email {n}.",
|
||||
"errorFailureCheckLogs": "Gagal (periksa konsol / log)",
|
||||
"errorPartialFailureCheckLogs": "Kegagalan sebagian (periksa konsol / log)",
|
||||
"errorUserCreated": "Gagal membuat pengguna {n}.",
|
||||
"errorSendWelcomeEmail": "Gagal mengirim email selamat datang (periksa konsol / log)",
|
||||
"saveEmail": "Email disimpan.",
|
||||
"sentAnnouncement": "Pengumuman dikirim.",
|
||||
"errorSaveEmail": "Gagal menyimpan email."
|
||||
},
|
||||
"quantityStrings": {
|
||||
"modifySettingsFor": {
|
||||
"singular": "Ubah Setelan untuk {n} pengguna",
|
||||
"plural": "Ubah Setelan untuk {n} pengguna"
|
||||
},
|
||||
"deleteNUsers": {
|
||||
"singular": "Hapus {n} pengguna",
|
||||
"plural": "Hapus {n} pengguna"
|
||||
},
|
||||
"addUser": {
|
||||
"singular": "Tambahkan pengguna",
|
||||
"plural": "Tambahkan pengguna"
|
||||
},
|
||||
"deleteUser": {
|
||||
"singular": "Hapus pengguna",
|
||||
"plural": "Hapus pengguna"
|
||||
},
|
||||
"deletedUser": {
|
||||
"singular": "Menghapus {n} pengguna.",
|
||||
"plural": "Menghapus {n} pengguna."
|
||||
},
|
||||
"appliedSettings": {
|
||||
"singular": "Pengaturan diterapkan pada {n} pengguna.",
|
||||
"plural": "Pengaturan diterapkan pada {n} pengguna."
|
||||
},
|
||||
"announceTo": {
|
||||
"singular": "Umumkan kepada {n} pengguna",
|
||||
"plural": "Umumkan kepada {n} pengguna"
|
||||
}
|
||||
}
|
||||
}
|
||||
187
lang/admin/nl-nl.json
Normal file
@@ -0,0 +1,187 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Nederlands (NL)"
|
||||
},
|
||||
"strings": {
|
||||
"invites": "Uitnodigingen",
|
||||
"accounts": "Accounts",
|
||||
"settings": "Instellingen",
|
||||
"inviteDays": "Dagen",
|
||||
"inviteHours": "Uren",
|
||||
"inviteMinutes": "Minuten",
|
||||
"inviteNumberOfUses": "Aantal keer te gebruiken",
|
||||
"warning": "Waarschuwing",
|
||||
"inviteInfiniteUsesWarning": "ongelimiteerde uitnodigingen kunnen misbruikt worden",
|
||||
"inviteSendToEmail": "Stuur naar",
|
||||
"login": "Inloggen",
|
||||
"logout": "Uitloggen",
|
||||
"create": "Aanmaken",
|
||||
"apply": "Toepassen",
|
||||
"delete": "Verwijderen",
|
||||
"name": "Naam",
|
||||
"date": "Datum",
|
||||
"lastActiveTime": "Laatst actief",
|
||||
"from": "Van",
|
||||
"user": "Gebruiker",
|
||||
"aboutProgram": "Over",
|
||||
"version": "Versie",
|
||||
"commitNoun": "Commit",
|
||||
"newUser": "Nieuwe gebruiker",
|
||||
"profile": "Profiel",
|
||||
"unknown": "Onbekend",
|
||||
"modifySettings": "Instellingen aanpassen",
|
||||
"modifySettingsDescription": "Pas instellingen van een bestaand profiel toe, of neem ze direct over van een gebruiker.",
|
||||
"applyHomescreenLayout": "Sla startpagina indeling op",
|
||||
"sendDeleteNotificationEmail": "Stuur meldingse-mail",
|
||||
"sendDeleteNotifiationExample": "Je account is verwijderd.",
|
||||
"settingsRestartRequired": "Herstart nodig",
|
||||
"settingsRestartRequiredDescription": "Er is een herstart nodig om de wijzigingen door te voeren. Herstart nu of later?",
|
||||
"settingsApplyRestartLater": "Sla op, herstart later",
|
||||
"settingsApplyRestartNow": "Sla op & herstart",
|
||||
"settingsApplied": "Wijzigingen doorgevoerd.",
|
||||
"settingsRefreshPage": "Ververs de pagina over enkele seconden.",
|
||||
"settingsRequiredOrRestartMessage": "Opmerking: {n} is een verplicht veld, {n} geeft aan dat na wijzigen een herstart nodig is.",
|
||||
"settingsSave": "Opslaan",
|
||||
"ombiUserDefaults": "Ombi gebruiker standaardinstellingen",
|
||||
"ombiUserDefaultsDescription": "Maak een Ombi gebruiker aan met de gewenste instellingen, en selecteer deze hieronder. Deze instellingen/rechten worden opgeslagen en toegepast voor nieuwe Ombi gebruikers die jfa-go aanmaakt",
|
||||
"userProfiles": "Gebruikersprofielen",
|
||||
"userProfilesDescription": "Profielen worden toegepast op gebruikers wanneer ze een account aanmaken. Een profiel bevat rechten voor bibliotheken en indeling van de startpagina.",
|
||||
"userProfilesIsDefault": "Standaard",
|
||||
"userProfilesLibraries": "Bibliotheken",
|
||||
"addProfile": "Voer profiel toe",
|
||||
"addProfileDescription": "Maak een Jellyfin gebruiker aan met de gewenste instellingen en selecteer deze hieronder. Wanneer dit profiel wordt toegepast op een uitnodiging, worden nieuwe gebruikers aangemaakt met deze instellingen.",
|
||||
"addProfileNameOf": "Profielnaam",
|
||||
"addProfileStoreHomescreenLayout": "Sla startpaginaindeling op",
|
||||
"inviteNoUsersCreated": "Nog geen!",
|
||||
"inviteUsersCreated": "Aangemaakte gebruikers",
|
||||
"inviteNoProfile": "Geen profiel",
|
||||
"inviteDateCreated": "Aangemaakt",
|
||||
"inviteRemainingUses": "Resterend aantal keer te gebruiken",
|
||||
"inviteNoInvites": "Geen",
|
||||
"inviteExpiresInTime": "Verloopt over {n}",
|
||||
"notifyEvent": "Meldingen:",
|
||||
"notifyInviteExpiry": "Bij verloop",
|
||||
"notifyUserCreation": "Bij aanmaken gebruiker",
|
||||
"label": "Label",
|
||||
"settingsRestart": "Herstart",
|
||||
"settingsRestarting": "Aan het herstarten…",
|
||||
"announce": "Aankondiging",
|
||||
"markdownSupported": "Markdown wordt ondersteund.",
|
||||
"subject": "E-mailonderwerp",
|
||||
"message": "Bericht",
|
||||
"variables": "Variabelen",
|
||||
"customizeMessagesDescription": "Als je de e-mailsjablonen van jfa-go niet wilt gebruiken, kun je met gebruik van Markdown je eigen aanmaken.",
|
||||
"preview": "Voorbeeld",
|
||||
"reset": "Resetten",
|
||||
"edit": "Bewerken",
|
||||
"customizeMessages": "E-mails aanpassen",
|
||||
"inviteDuration": "Geldigheidsduur uitnodiging",
|
||||
"userExpiryDescription": "Een bepaalde tijd na elke aanmelding, wordt de account verwijderd/uitgeschakeld door jfa-go. Dit kan aangepast worden in de instellingen.",
|
||||
"enabled": "Ingeschakeld",
|
||||
"disabled": "Uitgeschakeld",
|
||||
"admin": "Beheerder",
|
||||
"expiry": "Verloop",
|
||||
"userExpiry": "Gebruikersverloop",
|
||||
"extendExpiry": "Verleng verloop",
|
||||
"updates": "Updates",
|
||||
"update": "Bijwerken",
|
||||
"download": "Download",
|
||||
"search": "Zoeken",
|
||||
"advancedSettings": "Geavanceerde instellingen",
|
||||
"inviteMonths": "Maanden",
|
||||
"reEnable": "Opnieuw inschakelen",
|
||||
"disable": "Uitschakelen",
|
||||
"conditionals": "Voorwaarden"
|
||||
},
|
||||
"notifications": {
|
||||
"changedEmailAddress": "E-mailadres van {n} gewijzigd.",
|
||||
"userCreated": "Gebruiker {n} aangemaakt.",
|
||||
"createProfile": "Profiel {n} aangemaakt.",
|
||||
"saveSettings": "De instellingen zijn opgeslagen",
|
||||
"setOmbiDefaults": "De ombi standaardinstellingen zijn opgeslagen.",
|
||||
"errorConnection": "Kon geen verbinding maken met jfa-go.",
|
||||
"error401Unauthorized": "Geen toegang. Probeer de pagina te vernieuwen.",
|
||||
"errorSettingsAppliedNoHomescreenLayout": "De instellingen zijn toegepast, maar wijzigen van de startpaginaindeling is misschien mislukt.",
|
||||
"errorHomescreenAppliedNoSettings": "Startpaginaindeling toegepast, maar opslaan van instellingen is misschien mislukt.",
|
||||
"errorSettingsFailed": "Opslaan mislukt.",
|
||||
"errorLoginBlank": "De gebruikersnaam en/of wachtwoord is leeg.",
|
||||
"errorUnknown": "Onbekende fout.",
|
||||
"errorBlankFields": "Velden leeggelaten",
|
||||
"errorDeleteProfile": "Verwijderen van profiel {n} mislukt",
|
||||
"errorLoadProfiles": "Fout bij het laden van profielen.",
|
||||
"errorCreateProfile": "Aanmaken van profile {n} mislukt",
|
||||
"errorSetDefaultProfile": "Fout bij instellen van standaardprofiel.",
|
||||
"errorLoadUsers": "Laden van gebruikers mislukt.",
|
||||
"errorSaveSettings": "Opslaan van instellingen mislukt.",
|
||||
"errorLoadSettings": "Laden van instellingen mislukt.",
|
||||
"errorSetOmbiDefaults": "Opslaan van ombi standaardinstellingen mislukt.",
|
||||
"errorLoadOmbiUsers": "Laden van ombi gebruikers mislukt.",
|
||||
"errorChangedEmailAddress": "Wijzigen van e-mailadres van {n} mislukt.",
|
||||
"errorFailureCheckLogs": "Mislukt (controleer console/logbestanden)",
|
||||
"errorPartialFailureCheckLogs": "Gedeeltelijke fout (controleer console/logbestanden)",
|
||||
"errorSendWelcomeEmail": "Versturen van welkomste-mail is mislukt (zie console/logs)",
|
||||
"errorUserCreated": "Aanmaken van gebruiker {n} is mislukt.",
|
||||
"sentAnnouncement": "Aankondiging verzonden.",
|
||||
"saveEmail": "E-mail opgeslagen.",
|
||||
"errorSaveEmail": "Opslaan van e-mail mislukt.",
|
||||
"updateApplied": "De update is geïnstalleerd, doe alsjeblieft een herstart.",
|
||||
"errorApplyUpdate": "Installatie van update mislukt, probeer handmatig.",
|
||||
"errorCheckUpdate": "Controleren op update mislukt.",
|
||||
"updateAvailable": "Er is een nieuwe update beschikbaar, kijk bij instellingen.",
|
||||
"noUpdatesAvailable": "Geen nieuwe updates beschikbaar."
|
||||
},
|
||||
"quantityStrings": {
|
||||
"modifySettingsFor": {
|
||||
"singular": "Wijzig instellingen voor {n} gebruiker",
|
||||
"plural": "Wijzig instellingen voor {n} gebruikers"
|
||||
},
|
||||
"deleteNUsers": {
|
||||
"singular": "Verwijder {n} gebruiker",
|
||||
"plural": "Verwijder {n} gebruikers"
|
||||
},
|
||||
"addUser": {
|
||||
"singular": "Voeg gebruiker toe",
|
||||
"plural": "Voer gebruikers toe"
|
||||
},
|
||||
"deleteUser": {
|
||||
"singular": "Verwijder gebruiker",
|
||||
"plural": "Verwijder gebruikers"
|
||||
},
|
||||
"deletedUser": {
|
||||
"singular": "{n} gebruiker verwijderd.",
|
||||
"plural": "{n} gebruikers verwijderd."
|
||||
},
|
||||
"appliedSettings": {
|
||||
"singular": "Instellingen toegepast op {n} gebruiker.",
|
||||
"plural": "Instellingen toegepast op {n} gebruikers."
|
||||
},
|
||||
"announceTo": {
|
||||
"singular": "Aankondigen aan {n} gebruikers",
|
||||
"plural": "aankondigen aan {n} gebruikerss"
|
||||
},
|
||||
"extendExpiry": {
|
||||
"singular": "Verleng verloop voor {n} gebruiker",
|
||||
"plural": "Verleng verloop voor {n} gebruikers"
|
||||
},
|
||||
"extendedExpiry": {
|
||||
"singular": "Verloop uitgesteld voor {n} gebruiker.",
|
||||
"plural": "Verloop uitgesteld voor {n} gebruikers."
|
||||
},
|
||||
"disableUsers": {
|
||||
"singular": "Schakel {n} gebruiker uit",
|
||||
"plural": "Schakel {n} gebruikers uit"
|
||||
},
|
||||
"reEnableUsers": {
|
||||
"singular": "Schakel {n} gebruiker opnieuw in",
|
||||
"plural": "Schakel {n} gebruikers opnieuw in"
|
||||
},
|
||||
"disabledUser": {
|
||||
"singular": "{n} gebruiker uitgeschakeld.",
|
||||
"plural": "{n} gebruikers uitgeschakeld."
|
||||
},
|
||||
"enabledUser": {
|
||||
"singular": "{n} gebruiker ingeschakeld.",
|
||||
"plural": "{n} gebruikers ingeschakeld."
|
||||
}
|
||||
}
|
||||
}
|
||||
187
lang/admin/pt-br.json
Normal file
@@ -0,0 +1,187 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Português (BR)"
|
||||
},
|
||||
"strings": {
|
||||
"invites": "Convites",
|
||||
"accounts": "Contas",
|
||||
"settings": "Configurações",
|
||||
"inviteDays": "Dias",
|
||||
"inviteHours": "Horas",
|
||||
"inviteMinutes": "Minutos",
|
||||
"inviteNumberOfUses": "Números de usuários",
|
||||
"warning": "Aviso",
|
||||
"inviteInfiniteUsesWarning": "convites infinitos podem ser usados de forma abusiva",
|
||||
"inviteSendToEmail": "Enviar para",
|
||||
"login": "Login",
|
||||
"logout": "Sair",
|
||||
"create": "Criar",
|
||||
"apply": "Aplicar",
|
||||
"delete": "Deletar",
|
||||
"name": "Nome",
|
||||
"date": "Data",
|
||||
"lastActiveTime": "Ativo pela última vez",
|
||||
"from": "De",
|
||||
"user": "Usuário",
|
||||
"aboutProgram": "Sobre",
|
||||
"version": "Versão",
|
||||
"commitNoun": "Commit",
|
||||
"newUser": "Novo Usuário",
|
||||
"profile": "Perfil",
|
||||
"unknown": "Desconhecido",
|
||||
"label": "Rótulo",
|
||||
"modifySettings": "Modificar configurações",
|
||||
"modifySettingsDescription": "Aplique as configurações de um perfil existente ou obtenha-as diretamente de um usuário.",
|
||||
"applyHomescreenLayout": "Aplicar layout na tela inicial",
|
||||
"sendDeleteNotificationEmail": "Enviar email de notificação",
|
||||
"sendDeleteNotifiationExample": "Sua conta foi deletada.",
|
||||
"settingsRestartRequired": "Necessário reiniciar",
|
||||
"settingsRestartRequiredDescription": "É necessário reiniciar para aplicar algumas configurações alteradas. Deseja reiniciar agora ou mais tarde?",
|
||||
"settingsApplyRestartLater": "Aplicar, reiniciar mais tarde",
|
||||
"settingsApplyRestartNow": "Aplicar e reiniciar",
|
||||
"settingsApplied": "Configurações aplicada.",
|
||||
"settingsRefreshPage": "Atualize a página em alguns segundos.",
|
||||
"settingsRequiredOrRestartMessage": "Nota: {n} indica campo obrigatório, {n} indica que as alterações requer um reinício.",
|
||||
"settingsSave": "Salve",
|
||||
"ombiUserDefaults": "Padrões do usuário Ombi",
|
||||
"ombiUserDefaultsDescription": "Crie um usuário Ombi, configure-o e selecione-o abaixo. Suas configurações/permissões serão armazenadas e aplicadas aos novos usuários Ombi criados pelo jfa-go",
|
||||
"userProfiles": "Perfil de usuário",
|
||||
"userProfilesDescription": "Os perfis são aplicados aos usuários quando eles criam uma conta. Um perfil inclui direitos de acesso à biblioteca e layout da tela inicial.",
|
||||
"userProfilesIsDefault": "Padrão",
|
||||
"userProfilesLibraries": "Bibliotecas",
|
||||
"addProfile": "Adicionar Perfil",
|
||||
"addProfileDescription": "Crie um usuário no Jellyfin, configure e selecione abaixo. Quando este perfil é aplicado a um convite, novos usuários serão criados com as mesma configurações.",
|
||||
"addProfileNameOf": "Nome do perfil",
|
||||
"addProfileStoreHomescreenLayout": "Layout da tela inicial da loja",
|
||||
"inviteNoUsersCreated": "Nenhum ainda!",
|
||||
"inviteUsersCreated": "Usuários criado",
|
||||
"inviteNoProfile": "Sem Perfil",
|
||||
"inviteDateCreated": "Criado",
|
||||
"inviteRemainingUses": "Uso restantes",
|
||||
"inviteNoInvites": "Nenhum",
|
||||
"inviteExpiresInTime": "Expira em {n}",
|
||||
"notifyEvent": "Notificar em:",
|
||||
"notifyInviteExpiry": "No vencimento",
|
||||
"notifyUserCreation": "Na criação do usuário",
|
||||
"settingsRestart": "Reiniciar",
|
||||
"settingsRestarting": "Reiniciando…",
|
||||
"announce": "Anunciar",
|
||||
"subject": "Assunto do email",
|
||||
"message": "Mensagem",
|
||||
"markdownSupported": "Suporte a Markdown.",
|
||||
"customizeMessagesDescription": "Se não quiser usar os modelos de email do jfa-go, você pode criar o seu próprio usando o Markdown.",
|
||||
"variables": "Variáveis",
|
||||
"preview": "Pre-visualizar",
|
||||
"reset": "Reiniciar",
|
||||
"edit": "Editar",
|
||||
"customizeMessages": "Customizar Emails",
|
||||
"disabled": "Desativado",
|
||||
"userExpiryDescription": "Após um determinado período de tempo de cada inscrição, o jfa-go apagará/desabilitará a conta. Você pode alterar essa opção nas configurações.",
|
||||
"inviteDuration": "Duração do Convite",
|
||||
"enabled": "Habilitado",
|
||||
"admin": "Admin",
|
||||
"expiry": "Expira",
|
||||
"userExpiry": "Vencimento do Usuário",
|
||||
"extendExpiry": "Extender o vencimento",
|
||||
"updates": "Atualizações",
|
||||
"update": "Atualizar",
|
||||
"download": "Download",
|
||||
"search": "Procurar",
|
||||
"advancedSettings": "Configurações Avançada",
|
||||
"inviteMonths": "Meses",
|
||||
"reEnable": "Reativar",
|
||||
"disable": "Desativar",
|
||||
"conditionals": "Condicionais"
|
||||
},
|
||||
"notifications": {
|
||||
"changedEmailAddress": "Endereço de e-mail alterado de {n}.",
|
||||
"userCreated": "Usuário {n} criado.",
|
||||
"createProfile": "Perfil {n} criado.",
|
||||
"saveSettings": "As configurações foram salvas",
|
||||
"setOmbiDefaults": "Padrões do ombi armazenados.",
|
||||
"errorConnection": "Não foi possível conectar ao jfa-go.",
|
||||
"error401Unauthorized": "Não autorizado. Tente atualizar a página.",
|
||||
"errorSettingsAppliedNoHomescreenLayout": "As configurações foram aplicadas, mas a aplicação do layout da tela inicial pode ter falhado.",
|
||||
"errorHomescreenAppliedNoSettings": "O layout da tela inicial foi aplicado, mas a aplicação das configurações pode ter falhado.",
|
||||
"errorSettingsFailed": "Falha na aplicação.",
|
||||
"errorLoginBlank": "O nome de usuário e/ou senha foram deixados em branco.",
|
||||
"errorUnknown": "Erro desconhecido.",
|
||||
"errorBlankFields": "Os campos foram deixados em branco",
|
||||
"errorDeleteProfile": "Falha ao excluir perfil {n}",
|
||||
"errorLoadProfiles": "Falha ao carregar perfis.",
|
||||
"errorCreateProfile": "Falha ao criar perfil {n}",
|
||||
"errorSetDefaultProfile": "Falha ao definir o perfil padrão.",
|
||||
"errorLoadUsers": "Falha ao carregar usuários.",
|
||||
"errorSaveSettings": "Não foi possível salvar as configurações.",
|
||||
"errorLoadSettings": "Falha ao carregar as configurações.",
|
||||
"errorSetOmbiDefaults": "Falha em armazenar os padrões ombi.",
|
||||
"errorLoadOmbiUsers": "Falha ao carregar usuários ombi.",
|
||||
"errorChangedEmailAddress": "Não foi possível alterar o endereço de e-mail de {n}.",
|
||||
"errorFailureCheckLogs": "Falha (verificar console/logs)",
|
||||
"errorPartialFailureCheckLogs": "Falha parcial (verificar console/logs)",
|
||||
"errorUserCreated": "Falha ao criar o usuário {n}.",
|
||||
"errorSendWelcomeEmail": "Falha ao enviar e-mail de boas-vindas (verifique console/logs)",
|
||||
"sentAnnouncement": "Comunicado enviado.",
|
||||
"saveEmail": "Email salvo.",
|
||||
"errorSaveEmail": "Falha ao salvar o email.",
|
||||
"updateApplied": "Atualização aplicada, reinicie.",
|
||||
"errorApplyUpdate": "Falha ao aplicar a atualização, tente manualmente.",
|
||||
"updateAvailable": "Uma nova atualização está disponível, verifique as configurações.",
|
||||
"errorCheckUpdate": "Falha ao verificar atualizações.",
|
||||
"noUpdatesAvailable": "Nenhuma atualização disponível."
|
||||
},
|
||||
"quantityStrings": {
|
||||
"modifySettingsFor": {
|
||||
"singular": "Modificar configurações para usuário {n}",
|
||||
"plural": "Modificar configurações para usuários {n}"
|
||||
},
|
||||
"deleteNUsers": {
|
||||
"singular": "Excluir usuário {n}",
|
||||
"plural": "Excluir usuários {n}"
|
||||
},
|
||||
"addUser": {
|
||||
"singular": "Adicionar usuário",
|
||||
"plural": "Adicionar usuários"
|
||||
},
|
||||
"deleteUser": {
|
||||
"singular": "Deletar Usuário",
|
||||
"plural": "Deletar Usuários"
|
||||
},
|
||||
"deletedUser": {
|
||||
"singular": "Excluiu usuário {n}.",
|
||||
"plural": "Excluiu usuários {n}."
|
||||
},
|
||||
"appliedSettings": {
|
||||
"singular": "Configurações aplicada ao usuário {n}.",
|
||||
"plural": "Configurações aplicada ao usuários {n}."
|
||||
},
|
||||
"announceTo": {
|
||||
"singular": "Comunicar o usuário {n}",
|
||||
"plural": "Comunicar os usuários {n}"
|
||||
},
|
||||
"extendExpiry": {
|
||||
"singular": "Extender o vencimento para {n}",
|
||||
"plural": "Extender o vencimento para {n} usuários"
|
||||
},
|
||||
"extendedExpiry": {
|
||||
"plural": "Extender o vencimento para {n} usuários.",
|
||||
"singular": "Extender vencimento para {n}."
|
||||
},
|
||||
"disableUsers": {
|
||||
"singular": "Desativar {n} usuário",
|
||||
"plural": "Desativar {n} usuários"
|
||||
},
|
||||
"reEnableUsers": {
|
||||
"singular": "Reativar {n} usuário",
|
||||
"plural": "Reativar {n} usuários"
|
||||
},
|
||||
"disabledUser": {
|
||||
"singular": "{n} Usuário desativado.",
|
||||
"plural": "{n} usuários desativado."
|
||||
},
|
||||
"enabledUser": {
|
||||
"singular": "{n} Usuário habilitado.",
|
||||
"plural": "{n} Usuários habilitado."
|
||||
}
|
||||
}
|
||||
}
|
||||
157
lang/admin/sv-se.json
Normal file
@@ -0,0 +1,157 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Svenska (SV)"
|
||||
},
|
||||
"strings": {
|
||||
"invites": "Inbjudningar",
|
||||
"accounts": "Konton",
|
||||
"settings": "Inställningar",
|
||||
"inviteDays": "Dagar",
|
||||
"inviteHours": "Timmar",
|
||||
"inviteMinutes": "Minuter",
|
||||
"inviteNumberOfUses": "Antal användningar",
|
||||
"warning": "Varning",
|
||||
"inviteInfiniteUsesWarning": "inbjudningar med oändligt antal användningar kan missbrukas",
|
||||
"inviteSendToEmail": "Skicka till",
|
||||
"login": "Logga in",
|
||||
"logout": "Logga ut",
|
||||
"create": "Skapa",
|
||||
"apply": "Tillämpa",
|
||||
"delete": "Radera",
|
||||
"name": "Namn",
|
||||
"date": "Datum",
|
||||
"lastActiveTime": "Senast aktiv",
|
||||
"from": "Från",
|
||||
"user": "Användare",
|
||||
"aboutProgram": "Om",
|
||||
"version": "Version",
|
||||
"commitNoun": "Skicka",
|
||||
"newUser": "Ny användare",
|
||||
"profile": "Profil",
|
||||
"unknown": "Okänd",
|
||||
"label": "Etikett",
|
||||
"announce": "Meddela",
|
||||
"subject": "E-postämne",
|
||||
"message": "Meddelande",
|
||||
"variables": "Variabler",
|
||||
"preview": "Förhandsvisning",
|
||||
"reset": "Återställ",
|
||||
"edit": "Redigera",
|
||||
"customizeMessages": "Anpassa e-post",
|
||||
"customizeMessagesDescription": "Om du inte vill använda jfa-go's e-postmallar, så kan du skapa dina egna med Markdown.",
|
||||
"markdownSupported": "Markdown stöds.",
|
||||
"modifySettings": "Ändra inställningar",
|
||||
"modifySettingsDescription": "Tillämpa inställningar från en befintlig profil eller kopiera dem direkt från en användare.",
|
||||
"applyHomescreenLayout": "Tillämpa hemskärmslayout",
|
||||
"sendDeleteNotificationEmail": "Skicka notifikations e-postmeddelande",
|
||||
"sendDeleteNotifiationExample": "Ditt konto har raderats.",
|
||||
"settingsRestart": "Omstart",
|
||||
"settingsRestarting": "Startar om…",
|
||||
"settingsRestartRequired": "Omstart krävs",
|
||||
"settingsRestartRequiredDescription": "En omstart är nödvändig för att tillämpa vissa inställningar du ändrat. Starta om nu eller senare?",
|
||||
"settingsApplyRestartLater": "Tillämpa, men starta om senare",
|
||||
"settingsApplyRestartNow": "Tillämpa och starta om",
|
||||
"settingsApplied": "Inställningarna tillämpade.",
|
||||
"settingsRefreshPage": "Uppdatera sidan om några sekunder.",
|
||||
"settingsRequiredOrRestartMessage": "Notera: {n} anger ett obligatoriskt fält, {n} anger att ändringar kräver omstart.",
|
||||
"settingsSave": "Spara",
|
||||
"ombiUserDefaults": "Ombi standardanvändare",
|
||||
"ombiUserDefaultsDescription": "Skapa en Ombi-användare och konfigurera denna, välj sedan denna här nedan. Inställningar/behörigheter lagras och tillämpas på nya Ombi-användare som skapats av jfa-go",
|
||||
"userProfiles": "Användarprofiler",
|
||||
"userProfilesDescription": "Profiler tillämpas på användare när de skapar ett konto. En profil inkluderar biblioteksåtkomsträttigheter och layout på hemskärmen.",
|
||||
"userProfilesIsDefault": "Standard",
|
||||
"userProfilesLibraries": "Bibliotek",
|
||||
"addProfile": "Lägg till profil",
|
||||
"addProfileDescription": "Skapa en Jellyfin-användare och konfigurera samt välj denna här nedan. När den här profilen tillämpas på en inbjudan skapas nya användare med inställningarna.",
|
||||
"addProfileNameOf": "Profilnamn",
|
||||
"addProfileStoreHomescreenLayout": "Lagra hemskärmslayout",
|
||||
"inviteNoUsersCreated": "Ingen än!",
|
||||
"inviteUsersCreated": "Skapade användare",
|
||||
"inviteNoProfile": "Ingen profil",
|
||||
"inviteDateCreated": "Skapad",
|
||||
"inviteRemainingUses": "Återstående användningar",
|
||||
"inviteNoInvites": "Ingen",
|
||||
"inviteExpiresInTime": "Går ut om {n}",
|
||||
"notifyEvent": "Meddela den:",
|
||||
"notifyInviteExpiry": "Vid utgång",
|
||||
"notifyUserCreation": "Vid användarskapande",
|
||||
"disabled": "Inaktiverad",
|
||||
"enabled": "Aktiverad",
|
||||
"inviteDuration": "Varaktighet för inbjudan",
|
||||
"admin": "Admin",
|
||||
"expiry": "Löper ut",
|
||||
"userExpiry": "Användarutgång",
|
||||
"userExpiryDescription": "Efter en angiven tid efter varje registrering så tar jfa-go bort/inaktiverar kontot. Du kan ändra detta beteende i inställningarna.",
|
||||
"extendExpiry": "Förläng utgång"
|
||||
},
|
||||
"notifications": {
|
||||
"changedEmailAddress": "Ändrad e-postadress för {n}.",
|
||||
"userCreated": "Användaren {n} har skapats.",
|
||||
"createProfile": "Skapad profil {n}.",
|
||||
"saveSettings": "Inställningar sparades",
|
||||
"saveEmail": "E-post sparad.",
|
||||
"sentAnnouncement": "Meddelande skickat.",
|
||||
"setOmbiDefaults": "Lagrade ombi-standardvärden.",
|
||||
"errorConnection": "Det gick inte att ansluta till jfa-go.",
|
||||
"error401Unauthorized": "Obehörig. Prova att uppdatera sidan.",
|
||||
"errorSettingsAppliedNoHomescreenLayout": "Inställningarna tillämpades, men tillämpningen av hemskärmslayout kan ha misslyckats.",
|
||||
"errorHomescreenAppliedNoSettings": "Hemskärmslayout tillämpades, men tillämpningen av inställningar kan ha misslyckats.",
|
||||
"errorSettingsFailed": "Tillämpning misslyckades.",
|
||||
"errorLoginBlank": "Användarnamnet och/eller lösenordet lämnades tomt.",
|
||||
"errorUnknown": "Okänt fel.",
|
||||
"errorSaveEmail": "Det gick inte att spara e-postmeddelandet.",
|
||||
"errorBlankFields": "Fält lämnades tomma",
|
||||
"errorDeleteProfile": "Det gick inte att ta bort profilen {n}",
|
||||
"errorLoadProfiles": "Det gick inte att läsa in profiler.",
|
||||
"errorCreateProfile": "Det gick inte att skapa profilen {n}",
|
||||
"errorSetDefaultProfile": "Det gick inte att ange standardprofil.",
|
||||
"errorLoadUsers": "Det gick inte att läsa in användare.",
|
||||
"errorSaveSettings": "Det gick inte att spara inställningarna.",
|
||||
"errorLoadSettings": "Det gick inte att läsa in inställningarna.",
|
||||
"errorSetOmbiDefaults": "Det gick inte att lagra ombi-standardvärden.",
|
||||
"errorLoadOmbiUsers": "Det gick inte att ladda ombi-användare.",
|
||||
"errorChangedEmailAddress": "Det gick inte att ändra e-postadressen för {n}.",
|
||||
"errorFailureCheckLogs": "Misslyckades (kontrollera konsol/loggar)",
|
||||
"errorPartialFailureCheckLogs": "Partiellt fel (kontrollera konsol/loggarna)",
|
||||
"errorUserCreated": "Det gick inte att skapa användaren {n}.",
|
||||
"errorSendWelcomeEmail": "Det gick inte att skicka välkomstmail (kontrollera konsol/loggar)"
|
||||
},
|
||||
"quantityStrings": {
|
||||
"modifySettingsFor": {
|
||||
"singular": "Ändra inställningar för {n} användare",
|
||||
"plural": "Ändra inställningar för {n} användare"
|
||||
},
|
||||
"deleteNUsers": {
|
||||
"singular": "Ta bort {n} användare",
|
||||
"plural": "Ta bort {n} användare"
|
||||
},
|
||||
"addUser": {
|
||||
"singular": "Lägg till användare",
|
||||
"plural": "Lägg till användare"
|
||||
},
|
||||
"deleteUser": {
|
||||
"singular": "Radera användare",
|
||||
"plural": "Radera användare"
|
||||
},
|
||||
"deletedUser": {
|
||||
"singular": "{N} användare borttagen.",
|
||||
"plural": "{N} användare har tagits bort."
|
||||
},
|
||||
"announceTo": {
|
||||
"singular": "Meddela till {n} användare",
|
||||
"plural": "Meddela till {n} användare"
|
||||
},
|
||||
"appliedSettings": {
|
||||
"singular": "Tillämpade inställningar för {n} användare.",
|
||||
"plural": "Tillämpade inställningar för {n} användare."
|
||||
},
|
||||
"extendExpiry": {
|
||||
"plural": "Förläng utgången för {n} användare",
|
||||
"singular": "Förläng utgången för {n} användare"
|
||||
},
|
||||
"extendedExpiry": {
|
||||
"singular": "Utökad giltighetstid för {n} användare.",
|
||||
"plural": "Utökad giltighetstid för {n} användare."
|
||||
}
|
||||
}
|
||||
}
|
||||
19
lang/common/de-de.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Deutsch (DE)"
|
||||
},
|
||||
"strings": {
|
||||
"username": "Benutzername",
|
||||
"name": "Name",
|
||||
"password": "Passwort",
|
||||
"emailAddress": "E-Mail-Adresse",
|
||||
"submit": "Absenden",
|
||||
"success": "Erfolgreich",
|
||||
"error": "Fehler",
|
||||
"copy": "Kopieren",
|
||||
"theme": "Thema",
|
||||
"time24h": "24h-Format",
|
||||
"time12h": "12h-Format",
|
||||
"copied": "Kopiert"
|
||||
}
|
||||
}
|
||||
19
lang/common/el-gr.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Ελληνικά (GR)"
|
||||
},
|
||||
"strings": {
|
||||
"username": "Όνομα Χρήστη",
|
||||
"password": "Κωδικός",
|
||||
"emailAddress": "Διεύθυνση Email",
|
||||
"name": "Όνομα",
|
||||
"submit": "Καταχώρηση",
|
||||
"success": "Επιτυχία",
|
||||
"error": "Σφάλμα",
|
||||
"copy": "Αντιγραφή",
|
||||
"theme": "Θέμα",
|
||||
"time24h": "24 Ώρες",
|
||||
"time12h": "12 Ώρες",
|
||||
"copied": "Αντιγράφηκε"
|
||||
}
|
||||
}
|
||||
5
lang/common/en-gb.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "English (GB)"
|
||||
}
|
||||
}
|
||||
22
lang/common/en-us.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "English (US)"
|
||||
},
|
||||
"strings": {
|
||||
"username": "Username",
|
||||
"password": "Password",
|
||||
"emailAddress": "Email Address",
|
||||
"name": "Name",
|
||||
"submit": "Submit",
|
||||
"success": "Success",
|
||||
"error": "Error",
|
||||
"copy": "Copy",
|
||||
"copied": "Copied",
|
||||
"time24h": "24h Time",
|
||||
"time12h": "12h Time",
|
||||
"linkTelegram": "Link Telegram",
|
||||
"contactEmail": "Contact through Email",
|
||||
"contactTelegram": "Contact through Telegram",
|
||||
"theme": "Theme"
|
||||
}
|
||||
}
|
||||
19
lang/common/es-es.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Español(ES)"
|
||||
},
|
||||
"strings": {
|
||||
"username": "Nombre de usuario",
|
||||
"password": "Contraseña",
|
||||
"emailAddress": "Dirección de correo electrónico",
|
||||
"name": "Nombre",
|
||||
"submit": "Enviar",
|
||||
"success": "Éxito",
|
||||
"error": "Error",
|
||||
"copy": "Copiar",
|
||||
"copied": "Copiado",
|
||||
"time24h": "24 horas",
|
||||
"time12h": "24 horas",
|
||||
"theme": "Tema"
|
||||
}
|
||||
}
|
||||
19
lang/common/fr-fr.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Français (FR)",
|
||||
"author": "https://github.com/Killianbe"
|
||||
},
|
||||
"strings": {
|
||||
"username": "Nom d'utilisateur",
|
||||
"name": "Nom",
|
||||
"password": "Mot de passe",
|
||||
"emailAddress": "Addresse Email",
|
||||
"submit": "Soumettre",
|
||||
"success": "Succès",
|
||||
"error": "Erreur",
|
||||
"copy": "Copier",
|
||||
"time24h": "Temps 24h",
|
||||
"time12h": "Temps 12h",
|
||||
"theme": "Thème"
|
||||
}
|
||||
}
|
||||
18
lang/common/id-id.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Bahasa Indonesia (ID)"
|
||||
},
|
||||
"strings": {
|
||||
"username": "Nama pengguna",
|
||||
"password": "Sandi",
|
||||
"emailAddress": "Alamat Email",
|
||||
"name": "Nama",
|
||||
"submit": "Submit",
|
||||
"success": "Sukses",
|
||||
"error": "Error",
|
||||
"copy": "Salin",
|
||||
"time24h": "Waktu 24 jam",
|
||||
"time12h": "Waktu 12 jam",
|
||||
"theme": "Tema"
|
||||
}
|
||||
}
|
||||
19
lang/common/nl-nl.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Nederlands (NL)"
|
||||
},
|
||||
"strings": {
|
||||
"username": "Gebruikersnaam",
|
||||
"name": "Naam",
|
||||
"password": "Wachtwoord",
|
||||
"emailAddress": "E-mailadres",
|
||||
"submit": "Verstuur",
|
||||
"success": "Success",
|
||||
"error": "Fout",
|
||||
"copy": "Kopiëer",
|
||||
"theme": "Thema",
|
||||
"time24h": "24u-formaat",
|
||||
"time12h": "12u-formaat",
|
||||
"copied": "Gekopieerd"
|
||||
}
|
||||
}
|
||||
19
lang/common/pt-br.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Português (BR)"
|
||||
},
|
||||
"strings": {
|
||||
"username": "Nome do Usuário",
|
||||
"name": "Nome",
|
||||
"password": "Senha",
|
||||
"emailAddress": "Endereço de Email",
|
||||
"submit": "Enviar",
|
||||
"success": "Sucesso",
|
||||
"error": "Erro",
|
||||
"copy": "Copiar",
|
||||
"theme": "Tema",
|
||||
"time24h": "Horário 24h",
|
||||
"time12h": "Horário 12h",
|
||||
"copied": "Copiado"
|
||||
}
|
||||
}
|
||||
18
lang/common/sv-se.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Svenska (SV)"
|
||||
},
|
||||
"strings": {
|
||||
"username": "Användarnamn",
|
||||
"password": "Lösenord",
|
||||
"emailAddress": "E-postadress",
|
||||
"name": "Namn",
|
||||
"submit": "Skicka",
|
||||
"success": "Lyckades",
|
||||
"error": "Fel",
|
||||
"copy": "Kopiera",
|
||||
"time24h": "24 timmarsklocka",
|
||||
"time12h": "12 timmarsklocka",
|
||||
"theme": "Tema"
|
||||
}
|
||||
}
|
||||
65
lang/email/de-de.json
Normal file
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Deutsch (DE)"
|
||||
},
|
||||
"strings": {
|
||||
"ifItWasNotYou": "Wenn du das nicht warst, ignoriere bitte diese E-Mail.",
|
||||
"reason": "Grund",
|
||||
"helloUser": "Hallo {username},"
|
||||
},
|
||||
"userCreated": {
|
||||
"title": "Mitteilung: Benutzer erstellt",
|
||||
"aUserWasCreated": "Ein Benutzer wurde unter Verwendung des Codes {code} erstellt.",
|
||||
"time": "Zeit",
|
||||
"notificationNotice": "Hinweis: Benachrichtigungs-E-Mails können auf dem Administrator-Dashboard umgeschalten werden.",
|
||||
"name": "Benutzererstellung"
|
||||
},
|
||||
"inviteExpiry": {
|
||||
"title": "Mitteilung: Invite abgelaufen",
|
||||
"inviteExpired": "Invite abgelaufen.",
|
||||
"expiredAt": "Code {code} lief um {time} ab.",
|
||||
"notificationNotice": "Hinweis: Benachrichtigungs-E-Mails können auf dem Administrator-Dashboard umgeschalten werden.",
|
||||
"name": "Invite Ablaufdatum"
|
||||
},
|
||||
"passwordReset": {
|
||||
"title": "Passwortzurücksetzung angefordert - Jellyfin",
|
||||
"someoneHasRequestedReset": "Jemand hat vor kurzem eine Passwortzurücksetzung auf Jellyfin angefordert.",
|
||||
"ifItWasYou": "Wenn du das warst, gib die PIN unten in die Eingabeaufforderung ein.",
|
||||
"codeExpiry": "Der Code wird am {date}, um {time} UTC ablaufen, was in {expiresInMinutes} ist.",
|
||||
"pin": "PIN",
|
||||
"name": "Passwortzurücksetzung"
|
||||
},
|
||||
"userDeleted": {
|
||||
"title": "Dein Konto wurde gelöscht - Jellyfin",
|
||||
"yourAccountWasDeleted": "Dein Jellyfin-Konto wurde gelöscht.",
|
||||
"name": "Benutzerlöschung"
|
||||
},
|
||||
"inviteEmail": {
|
||||
"title": "Invite - Jellyfin",
|
||||
"hello": "Hallo",
|
||||
"youHaveBeenInvited": "Du wurdest zu Jellyfin eingeladen.",
|
||||
"toJoin": "Um beizutreten, folge dem untenstehenden Link.",
|
||||
"inviteExpiry": "Dieser Invite wird am {date}; um {time} ablaufen, was in {expiresInMinutes} ist, also handle schnell.",
|
||||
"linkButton": "Richte dein Konto ein",
|
||||
"name": "Einladungs-E-Mail"
|
||||
},
|
||||
"welcomeEmail": {
|
||||
"title": "Wilkommen bei Jellyfin",
|
||||
"welcome": "Willkommen bei Jellyfin!",
|
||||
"youCanLoginWith": "Du kannst dich mit den mit den untenstehenden Zugangsdaten anmelden",
|
||||
"jellyfinURL": "URL",
|
||||
"name": "Willkommens-E-Mail"
|
||||
},
|
||||
"emailConfirmation": {
|
||||
"title": "Bestätige deine E-Mail - Jellyfin",
|
||||
"clickBelow": "Klicke den untenstehenden Link, um deine E-Mail-Adresse zu bestätigen, und fange an, Jellyfin zu benutzen.",
|
||||
"confirmEmail": "E-Mail bestätigen",
|
||||
"name": "Bestätigungs-E-Mail"
|
||||
},
|
||||
"userExpired": {
|
||||
"name": "Benutzer Ablaufdatum",
|
||||
"title": "Dein Konto ist abgelaufen - Jellyfin",
|
||||
"yourAccountHasExpired": "Dein Konto ist abgelaufen.",
|
||||
"contactTheAdmin": "Kontaktiere den Administrator für weitere Informationen."
|
||||
}
|
||||
}
|
||||
77
lang/email/el-gr.json
Normal file
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Ελληνικά (GR)"
|
||||
},
|
||||
"strings": {
|
||||
"ifItWasNotYou": "Αν δεν ήσασταν εσείς, παρακαλώ αγνοήστε αυτό το email.",
|
||||
"reason": "Λόγος",
|
||||
"helloUser": "Γεία σου {username},"
|
||||
},
|
||||
"userCreated": {
|
||||
"title": "Σημείωση: Δημιουργήθηκε χρήστης",
|
||||
"aUserWasCreated": "Δημιουργήθηκε ένας χρήστης χρησιμοποιώντας τον κωδικό {code}.",
|
||||
"time": "Ώρα",
|
||||
"notificationNotice": "Σημείωση: Τα email ειδοποιήσεων μπορούν να ενεργοποιηθούν στον πίνακα ελέγχου διαχειριστή.",
|
||||
"name": "Δημιουργία χρήστη"
|
||||
},
|
||||
"inviteExpiry": {
|
||||
"title": "Σημείωση: Η πρόσκληση έληξε",
|
||||
"inviteExpired": "Η πρόσκληση έληξε.",
|
||||
"expiredAt": "Ο κωδικός {code} έληξε στις {time}.",
|
||||
"notificationNotice": "Σημείωση: Τα email ειδοποιήσεων μπορούν να ενεργοποιηθούν στον πίνακα ελέγχου διαχειριστή.",
|
||||
"name": "Λήξη πρόσκλησης"
|
||||
},
|
||||
"passwordReset": {
|
||||
"title": "Ζητήθηκε επαναφορά κωδικού πρόσβασης - Jellyfin",
|
||||
"someoneHasRequestedReset": "Κάποιος ζήτησε πρόσφατα επαναφορά κωδικού πρόσβασης στο Jellyfin.",
|
||||
"ifItWasYou": "Εάν ήσασταν εσείς, εισαγάγετε το πιν στο πεδίο.",
|
||||
"codeExpiry": "Ο κωδικός θα λήξει στις {date}, στις {time} UTC, το οποίο είναι σε {expiresInMinutes}.",
|
||||
"pin": "PIN",
|
||||
"name": "Επαναφορά κωδικού πρόσβασης",
|
||||
"ifItWasYouLink": "Εάν ήσασταν εσείς, κάντε κλικ στον παρακάτω σύνδεσμο."
|
||||
},
|
||||
"userDeleted": {
|
||||
"title": "Ο λογαριασμός σας διαγράφηκε - Jellyfin",
|
||||
"yourAccountWasDeleted": "Ο λογαριασμός σας Jellyfin διαγράφηκε.",
|
||||
"name": "Διαγραφή χρήστη"
|
||||
},
|
||||
"inviteEmail": {
|
||||
"title": "Πρόσκληση - Jellyfin",
|
||||
"hello": "Γειά",
|
||||
"youHaveBeenInvited": "Έχετε προσκληθεί στο Jellyfin.",
|
||||
"toJoin": "Για να συμμετέχετε, ακολουθήστε τον παρακάτω σύνδεσμο.",
|
||||
"inviteExpiry": "Αυτή η πρόσκληση θα λήξει στις {date} στις {time}, που είναι σε {expiresInMinutes}, οπότε ενεργήστε γρήγορα.",
|
||||
"linkButton": "Ρυθμίστε τον λογαριασμό σας",
|
||||
"name": "Email πρόσκλησης"
|
||||
},
|
||||
"welcomeEmail": {
|
||||
"title": "Καλώς ήλθατε στο Jellyfin",
|
||||
"welcome": "Καλώς ήλθατε στο Jellyfin!",
|
||||
"youCanLoginWith": "Μπορείτε να συνδεθείτε με τα παρακάτω στοιχεία",
|
||||
"jellyfinURL": "URL",
|
||||
"name": "Email καλωσορίσματος",
|
||||
"yourAccountWillExpire": "Ο λογαριασμός σας θα λήξει στις {date}."
|
||||
},
|
||||
"emailConfirmation": {
|
||||
"title": "Επιβεβαιώστε το email σας - Jellyfin",
|
||||
"clickBelow": "Κάντε κλικ στον παρακάτω σύνδεσμο για να επιβεβαιώσετε τη διεύθυνση email σας και ξεκινήστε να χρησιμοποιείτε το Jellyfin.",
|
||||
"confirmEmail": "Επιβεβαίωση Email",
|
||||
"name": "Email επιβεβαίωσης"
|
||||
},
|
||||
"userExpired": {
|
||||
"name": "Λήξη Χρήστη",
|
||||
"title": "Ο λογαριασμός σας έληξε - Jellyfin",
|
||||
"yourAccountHasExpired": "Ο λογαριασμός σας έχει λήξει.",
|
||||
"contactTheAdmin": "Επικοινωνήστε με τον διαχειριστή για περισσότερες πληροφορίες."
|
||||
},
|
||||
"userDisabled": {
|
||||
"name": "Ο χρήστης απενεργοποιήθηκε",
|
||||
"title": "Ο λογαριασμός σας έχει απενεργοποιηθεί - Jellyfin",
|
||||
"yourAccountWasDisabled": "Ο λογαριασμός σας απενεργοποιήθηκε."
|
||||
},
|
||||
"userEnabled": {
|
||||
"title": "Ο λογαριασμός σας έχει ενεργοποιηθεί ξανά - Jellyfin",
|
||||
"name": "Ο χρήστης ενεργοποιήθηκε",
|
||||
"yourAccountWasEnabled": "Ο λογαριασμός σας ενεργοποιήθηκε εκ νέου."
|
||||
}
|
||||
}
|
||||
5
lang/email/en-gb.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "English (GB)"
|
||||
}
|
||||
}
|
||||
77
lang/email/en-us.json
Normal file
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "English (US)"
|
||||
},
|
||||
"strings": {
|
||||
"ifItWasNotYou": "If this wasn't you, please ignore this.",
|
||||
"helloUser": "Hi {username},",
|
||||
"reason": "Reason"
|
||||
},
|
||||
"userCreated": {
|
||||
"name": "User creation",
|
||||
"title": "Notice: User created",
|
||||
"aUserWasCreated": "A user was created using code {code}.",
|
||||
"time": "Time",
|
||||
"notificationNotice": "Note: Notification emails can be toggled on the admin dashboard."
|
||||
},
|
||||
"inviteExpiry": {
|
||||
"name": "Invite expiry",
|
||||
"title": "Notice: Invite expired",
|
||||
"inviteExpired": "Invite expired.",
|
||||
"expiredAt": "Code {code} expired at {time}.",
|
||||
"notificationNotice": "Note: Notification emails can be toggled on the admin dashboard."
|
||||
},
|
||||
"passwordReset": {
|
||||
"name": "Password reset",
|
||||
"title": "Password reset requested - Jellyfin",
|
||||
"someoneHasRequestedReset": "Someone has recently requested a password reset on Jellyfin.",
|
||||
"ifItWasYou": "If this was you, enter the pin below into the prompt.",
|
||||
"ifItWasYouLink": "If this was you, click the link below.",
|
||||
"codeExpiry": "The code will expire on {date}, at {time} UTC, which is in {expiresInMinutes}.",
|
||||
"pin": "PIN"
|
||||
},
|
||||
"userDeleted": {
|
||||
"name": "User deletion",
|
||||
"title": "Your account was deleted - Jellyfin",
|
||||
"yourAccountWasDeleted": "Your Jellyfin account was deleted."
|
||||
},
|
||||
"userDisabled": {
|
||||
"name": "User disabled",
|
||||
"title": "Your account has been disabled - Jellyfin",
|
||||
"yourAccountWasDisabled": "Your account was disabled."
|
||||
},
|
||||
"userEnabled": {
|
||||
"name": "User enabled",
|
||||
"title": "Your account has been re-enabled - Jellyfin",
|
||||
"yourAccountWasEnabled": "Your account was re-enabled."
|
||||
},
|
||||
"inviteEmail": {
|
||||
"name": "Invite email",
|
||||
"title": "Invite - Jellyfin",
|
||||
"hello": "Hi",
|
||||
"youHaveBeenInvited": "You've been invited to Jellyfin.",
|
||||
"toJoin": "To join, follow the below link.",
|
||||
"inviteExpiry": "This invite will expire on {date} at {time}, which is in {expiresInMinutes}, so act quick.",
|
||||
"linkButton": "Setup your account"
|
||||
},
|
||||
"welcomeEmail": {
|
||||
"name": "Welcome",
|
||||
"title": "Welcome to Jellyfin",
|
||||
"welcome": "Welcome to Jellyfin!",
|
||||
"youCanLoginWith": "You can login with the details below",
|
||||
"yourAccountWillExpire": "Your account will expire on {date}.",
|
||||
"jellyfinURL": "URL"
|
||||
},
|
||||
"emailConfirmation": {
|
||||
"name": "Confirmation email",
|
||||
"title": "Confirm your email - Jellyfin",
|
||||
"clickBelow": "Click the link below to confirm your email address and start using Jellyfin.",
|
||||
"confirmEmail": "Confirm Email"
|
||||
},
|
||||
"userExpired": {
|
||||
"name": "User expiry",
|
||||
"title": "Your account has expired - Jellyfin",
|
||||
"yourAccountHasExpired": "Your account has expired.",
|
||||
"contactTheAdmin": "Contact the administrator for more info."
|
||||
}
|
||||
}
|
||||
77
lang/email/es-es.json
Normal file
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Español(ES)"
|
||||
},
|
||||
"strings": {
|
||||
"ifItWasNotYou": "Si no fue usted, ignore este correo electrónico.",
|
||||
"helloUser": "Hola {username},",
|
||||
"reason": "Razón"
|
||||
},
|
||||
"userCreated": {
|
||||
"name": "Creación de usuarios",
|
||||
"title": "Noticia: Usuario creado",
|
||||
"aUserWasCreated": "Se creó un usuario con el código {code}.",
|
||||
"time": "Hora",
|
||||
"notificationNotice": "Nota: los correos electrónicos de notificación se pueden alternar en el panel de administración."
|
||||
},
|
||||
"inviteExpiry": {
|
||||
"name": "Vencimiento de la invitación",
|
||||
"title": "Aviso: Invitación caducada",
|
||||
"inviteExpired": "Invitación caducada.",
|
||||
"expiredAt": "El código {code} venció a las {time}.",
|
||||
"notificationNotice": "Nota: Los correos electrónicos de notificación se pueden alternar en el panel de administración."
|
||||
},
|
||||
"passwordReset": {
|
||||
"name": "Restablecimiento de contraseña",
|
||||
"title": "Solicitud de restablecimiento de contraseña - Jellyfin",
|
||||
"someoneHasRequestedReset": "Alguien ha solicitado recientemente un restablecimiento de contraseña en Jellyfin.",
|
||||
"ifItWasYou": "Si era usted, ingrese el pin a continuación en el mensaje.",
|
||||
"ifItWasYouLink": "Si fue usted, haga clic en el enlace de abajo.",
|
||||
"codeExpiry": "El código vencerá el {date}, a las {time} UTC, que está en {expiresInMinutes}.",
|
||||
"pin": "PIN"
|
||||
},
|
||||
"userDeleted": {
|
||||
"name": "Eliminación de usuario",
|
||||
"title": "Su cuenta fue eliminada - Jellyfin",
|
||||
"yourAccountWasDeleted": "Su cuenta de Jellyfin fue eliminada."
|
||||
},
|
||||
"userDisabled": {
|
||||
"name": "Usuario deshabilitado",
|
||||
"title": "Su cuenta ha sido deshabilitada - Jellyfin",
|
||||
"yourAccountWasDisabled": "Su cuenta fue inhabilitada."
|
||||
},
|
||||
"userEnabled": {
|
||||
"name": "Usuario habilitado",
|
||||
"title": "Su cuenta ha sido reactivada - Jellyfin",
|
||||
"yourAccountWasEnabled": "Su cuenta se volvió a habilitar."
|
||||
},
|
||||
"inviteEmail": {
|
||||
"name": "Correo electrónico",
|
||||
"title": "Invitar - Jellyfin",
|
||||
"hello": "Hola",
|
||||
"youHaveBeenInvited": "Has sido invitado a Jellyfin.",
|
||||
"toJoin": "Para unirse, siga el enlace a continuación.",
|
||||
"inviteExpiry": "Esta invitación vencerá el {date} a las {time}, que está en {expiresInMinutes}, así que regístrese cuanto antes.",
|
||||
"linkButton": "Configurar tu cuenta"
|
||||
},
|
||||
"welcomeEmail": {
|
||||
"name": "Correo de bienvenida",
|
||||
"title": "Bienvenido a Jellyfin",
|
||||
"welcome": "¡Bienvenido a Jellyfin!",
|
||||
"youCanLoginWith": "Puede iniciar sesión con los detalles a continuación",
|
||||
"yourAccountWillExpire": "Su cuenta vencerá el {date}.",
|
||||
"jellyfinURL": "URL"
|
||||
},
|
||||
"emailConfirmation": {
|
||||
"name": "Email de confirmación",
|
||||
"title": "Confirma tu correo electrónico - Jellyfin",
|
||||
"clickBelow": "Haga clic en el enlace de abajo para confirmar su dirección de correo electrónico y comenzar a usar Jellyfin.",
|
||||
"confirmEmail": "Confirmar correo electrónico"
|
||||
},
|
||||
"userExpired": {
|
||||
"name": "Caducidad del usuario",
|
||||
"title": "Tu cuenta ha caducado - Jellyfin",
|
||||
"yourAccountHasExpired": "Tu cuenta ha expirado.",
|
||||
"contactTheAdmin": "Comuníquese con el administrador para obtener más información."
|
||||
}
|
||||
}
|
||||
78
lang/email/fr-fr.json
Normal file
@@ -0,0 +1,78 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Français (FR)",
|
||||
"author": "https://github.com/Cornichon420"
|
||||
},
|
||||
"strings": {
|
||||
"ifItWasNotYou": "Si ce n'était pas toi, tu peux ignorer ce mail.",
|
||||
"reason": "Motif",
|
||||
"helloUser": "Salut {username},"
|
||||
},
|
||||
"userCreated": {
|
||||
"title": "Notification : Utilisateur créé",
|
||||
"aUserWasCreated": "Un utilisateur a été créé avec ce code {code}.",
|
||||
"time": "Date",
|
||||
"notificationNotice": "Note : Les emails de notification peuvent être activés sur le tableau de bord administrateur.",
|
||||
"name": "Création d'utilisateur"
|
||||
},
|
||||
"inviteExpiry": {
|
||||
"title": "Notification : Invitation expirée",
|
||||
"inviteExpired": "Invitation expirée.",
|
||||
"expiredAt": "Le code {code} a expiré à {time}.",
|
||||
"notificationNotice": "Note : Les emails de notification peuvent être activés sur le tableau de bord administrateur.",
|
||||
"name": "Expiration de l'invitation"
|
||||
},
|
||||
"passwordReset": {
|
||||
"title": "Réinitialisation de mot du passe demandée - Jellyfin",
|
||||
"someoneHasRequestedReset": "Quelqu'un vient de demander une réinitialisation du mot de passe via Jellyfin.",
|
||||
"ifItWasYou": "Si c'était bien toi, renseigne le code PIN en dessous.",
|
||||
"codeExpiry": "Ce code expirera le {date}, à {time} UTC, soit dans {expiresInMinutes}.",
|
||||
"pin": "PIN",
|
||||
"name": "Réinitialisation du mot de passe",
|
||||
"ifItWasYouLink": "Si c'était bien toi, clique sur le lien en dessous."
|
||||
},
|
||||
"userDeleted": {
|
||||
"title": "Ton compte a été désactivé - Jellyfin",
|
||||
"yourAccountWasDeleted": "Ton compte Jellyfin a été supprimé.",
|
||||
"name": "Suppression de l'utilisateur"
|
||||
},
|
||||
"inviteEmail": {
|
||||
"title": "Invitation - Jellyfin",
|
||||
"hello": "Salut",
|
||||
"youHaveBeenInvited": "Tu as été invité à rejoindre Jellyfin.",
|
||||
"toJoin": "Pour continuer, suis le lien en dessous.",
|
||||
"inviteExpiry": "L'invitation expirera le {date}, à {time}, soit dans {expiresInMinutes}, alors fais vite.",
|
||||
"linkButton": "Lien",
|
||||
"name": "Courriel d'invitation"
|
||||
},
|
||||
"welcomeEmail": {
|
||||
"youCanLoginWith": "Tu peux te connecter avec les informations ci-dessous",
|
||||
"title": "Bienvenue sur Jellyfin",
|
||||
"welcome": "Bienvenue sur Jellyfin !",
|
||||
"jellyfinURL": "URL",
|
||||
"name": "Courriel de bienvenue",
|
||||
"yourAccountWillExpire": "Ton compte expirera le {date}."
|
||||
},
|
||||
"emailConfirmation": {
|
||||
"title": "Confirmez votre adresse e-mail - Jellyfin",
|
||||
"clickBelow": "Clique sur le lien ci-dessous pour confirmer ton adresse e-mail et commencer à utiliser Jellyfin.",
|
||||
"confirmEmail": "Confirmer l'adresse e-mail",
|
||||
"name": "Email de confirmation"
|
||||
},
|
||||
"userExpired": {
|
||||
"contactTheAdmin": "Contacte l'administrateur pour plus d'informations.",
|
||||
"name": "Utilisateur expiré",
|
||||
"title": "Ton compte a expiré - Jellyfin",
|
||||
"yourAccountHasExpired": "Ton compte a expiré."
|
||||
},
|
||||
"userDisabled": {
|
||||
"name": "Utilisateur désactivé",
|
||||
"title": "Ton compte a été désactivé - Jellyfin",
|
||||
"yourAccountWasDisabled": "Ton compte a été désactivé."
|
||||
},
|
||||
"userEnabled": {
|
||||
"name": "Utilisateur activé",
|
||||
"title": "Ton compte a été ré-activé - Jellyfin",
|
||||
"yourAccountWasEnabled": "Ton compte a été ré-activé."
|
||||
}
|
||||
}
|
||||
59
lang/email/id-id.json
Normal file
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Bahasa Indonesia (ID)"
|
||||
},
|
||||
"strings": {
|
||||
"ifItWasNotYou": "Jika ini bukan kamu, silahkan mengabaikan email ini.",
|
||||
"reason": "Alasan",
|
||||
"helloUser": "Halo {username},"
|
||||
},
|
||||
"userCreated": {
|
||||
"title": "Perhatian: User telah dibuat",
|
||||
"aUserWasCreated": "User telah dibuat menggunakan kode {code}.",
|
||||
"time": "Waktu",
|
||||
"notificationNotice": "Catatan: Email notifikasi dapat diganti pada dasbor admin.",
|
||||
"name": "Pembuatan pengguna"
|
||||
},
|
||||
"inviteExpiry": {
|
||||
"title": "Perhatian: Undangan telah kadaluarsa",
|
||||
"inviteExpired": "Undangan telah kadaluarsa.",
|
||||
"expiredAt": "Kode {code} kadaluarsa pada {time}.",
|
||||
"notificationNotice": "Catatan: Email notifikasi dapat diganti pada dasbor admin.",
|
||||
"name": "Waktu kedaluwarsa undangan"
|
||||
},
|
||||
"passwordReset": {
|
||||
"title": "Reset password telah di-request - Jellyfin",
|
||||
"someoneHasRequestedReset": "Seseorang baru saja me-request reset password pada Jellyfin.",
|
||||
"ifItWasYou": "Jika ini adalah benar anda, masukkan pin dibawah ke dalam tempat yang sudah disediakan.",
|
||||
"codeExpiry": "Kode akan kadaluarsa pada {date}, pada waktu {time} UTC, yaitu dalam {expiresInMinutes}.",
|
||||
"pin": "PIN",
|
||||
"name": "Atur ulang kata sandi"
|
||||
},
|
||||
"userDeleted": {
|
||||
"title": "Akun anda telah dihapus - Jellyfin",
|
||||
"yourAccountWasDeleted": "Akun Jellyfin anda telah dihapus.",
|
||||
"name": "Penghapusan pengguna"
|
||||
},
|
||||
"inviteEmail": {
|
||||
"title": "Undangan - Jellyfin",
|
||||
"hello": "Halo",
|
||||
"youHaveBeenInvited": "Anda telah diundang ke Jellyfin.",
|
||||
"toJoin": "Untuk masuk, silahkan ikuti link dibawah ini.",
|
||||
"inviteExpiry": "Undangan ini akan berakhir dalam {date} pada {time}, yaitu dalam {expiresInMinutes}, jadi bergegaslah.",
|
||||
"linkButton": "Persiapkan akunmu",
|
||||
"name": "Email Undangan"
|
||||
},
|
||||
"welcomeEmail": {
|
||||
"title": "Selamat datang di Jellyfin",
|
||||
"welcome": "Selamat datang di Jellyfin!",
|
||||
"youCanLoginWith": "Anda dapat masuk dengan menggunakan data dibawah ini",
|
||||
"jellyfinURL": "URL",
|
||||
"name": "Email selamat datang"
|
||||
},
|
||||
"emailConfirmation": {
|
||||
"title": "Konfirmasi emailmu - Jellyfin",
|
||||
"clickBelow": "Klik link dibawah ini untuk mengkonfirmasikan alamat emailmu untuk mulai menggunakan Jellyfin.",
|
||||
"confirmEmail": "Konfirmasi Email",
|
||||
"name": "Email konfirmasi"
|
||||
}
|
||||
}
|
||||
52
lang/email/it-it.json
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Italiano (IT)"
|
||||
},
|
||||
"strings": {
|
||||
"ifItWasNotYou": "Se non sei stato tu, puoi ignorare questa email.",
|
||||
"helloUser": "Ciao {username},",
|
||||
"reason": "Motivo"
|
||||
},
|
||||
"userCreated": {
|
||||
"title": "Nota: Utente creato",
|
||||
"aUserWasCreated": "Un utente è stato creato usando il codice {code}.",
|
||||
"time": "Tempo",
|
||||
"notificationNotice": "Nota: Le notifiche via email possono essere attivate nel pannello di admin."
|
||||
},
|
||||
"inviteExpiry": {
|
||||
"title": "Nota: Invito scaduto",
|
||||
"inviteExpired": "Invito scaduto.",
|
||||
"expiredAt": "Il codice {code} è scaduto il {time}.",
|
||||
"notificationNotice": "Nota: le e-mail di notifica possono essere attivate dal pannello di admin."
|
||||
},
|
||||
"passwordReset": {
|
||||
"title": "Richiesto un reset della password - Jellyfin",
|
||||
"someoneHasRequestedReset": "Qualcuno ha recentemente richiesto un reset della password su Jellyfin.",
|
||||
"ifItWasYou": "Se sei stato tu, scrivi il PIN sotto alla richiesta.",
|
||||
"codeExpiry": "Il codice scadrà in {date}, alle {time} UTC, che è alle {expiresInMinutes}.",
|
||||
"pin": "PIN"
|
||||
},
|
||||
"userDeleted": {
|
||||
"title": "Il tuo account è stato eliminato - Jellyfin",
|
||||
"yourAccountWasDeleted": "Il tuo account di Jellyfin è stato eliminato."
|
||||
},
|
||||
"inviteEmail": {
|
||||
"title": "Invita - Jellyfin",
|
||||
"hello": "Salve",
|
||||
"youHaveBeenInvited": "Sei stato inviatato su Jellyfin.",
|
||||
"toJoin": "Per entrare, segui il link sotto.",
|
||||
"inviteExpiry": "",
|
||||
"linkButton": ""
|
||||
},
|
||||
"welcomeEmail": {
|
||||
"title": "",
|
||||
"welcome": "",
|
||||
"youCanLoginWith": "",
|
||||
"jellyfinURL": ""
|
||||
},
|
||||
"emailConfirmation": {
|
||||
"title": "",
|
||||
"clickBelow": "",
|
||||
"confirmEmail": ""
|
||||
}
|
||||
}
|
||||
77
lang/email/nl-nl.json
Normal file
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Nederlands (NL)"
|
||||
},
|
||||
"strings": {
|
||||
"ifItWasNotYou": "Als jij dit niet was, negeer dan alsjeblieft deze email.",
|
||||
"reason": "Reden",
|
||||
"helloUser": "Hoi {username},"
|
||||
},
|
||||
"userCreated": {
|
||||
"title": "Melding: Gebruiker aangemaakt",
|
||||
"aUserWasCreated": "Er is een gebruiker aangemaakt door gebruik te maken van code {code}.",
|
||||
"time": "Tijdstip",
|
||||
"notificationNotice": "Opmerking: Meldingse-mails kunnen worden aan- of uitgezet via het beheerdersdashboard.",
|
||||
"name": "Gebruiker aangemaakt"
|
||||
},
|
||||
"inviteExpiry": {
|
||||
"title": "Melding: Uitnodiging verlopen",
|
||||
"inviteExpired": "Uitnodiging verlopen.",
|
||||
"expiredAt": "Code {code} is verlopen op {time}.",
|
||||
"notificationNotice": "Opmerking: Meldingse-mails kunnen worden aan- of uitgezet via het beheerdersdashboard.",
|
||||
"name": "Uitnodiging verlopen"
|
||||
},
|
||||
"passwordReset": {
|
||||
"title": "Wachtwoordreset aangevraagd - Jellyfin",
|
||||
"someoneHasRequestedReset": "Iemand heeft recentelijk een wachtwoordreset aangevraagd in Jellyfin.",
|
||||
"ifItWasYou": "Als jij dit was, voer dan onderstaande PIN in.",
|
||||
"codeExpiry": "De code verloopt op {date}, op {time} UTC, dat is over {expiresInMinutes}.",
|
||||
"pin": "PIN",
|
||||
"name": "Wachtwoordreset",
|
||||
"ifItWasYouLink": "Als jij dit was, klik dan op onderstaande link."
|
||||
},
|
||||
"userDeleted": {
|
||||
"title": "Je account is verwijderd - Jellyfin",
|
||||
"yourAccountWasDeleted": "Je Jellyfin account is verwijderd.",
|
||||
"name": "Gebruiker verwijderd"
|
||||
},
|
||||
"inviteEmail": {
|
||||
"title": "Uitnodiging - Jellyfin",
|
||||
"hello": "Hoi",
|
||||
"youHaveBeenInvited": "Je bent uitgenodigd voor Jellyfin.",
|
||||
"toJoin": "Volg onderstaande link om door te gaan.",
|
||||
"inviteExpiry": "Deze uitnodiging verloopt op {date}, om {time}, dat is over {expiresInMinutes}, dus wees er snel bij.",
|
||||
"linkButton": "Maak account aan",
|
||||
"name": "Uitnodigingse-mail"
|
||||
},
|
||||
"welcomeEmail": {
|
||||
"title": "Welkom bij Jellyfin",
|
||||
"welcome": "Welkom bij Jellyfin!",
|
||||
"youCanLoginWith": "Je kunt inloggen met onderstaande gegevens",
|
||||
"jellyfinURL": "URL",
|
||||
"name": "Welkomste-mail",
|
||||
"yourAccountWillExpire": "Je account verloopt op {date}."
|
||||
},
|
||||
"emailConfirmation": {
|
||||
"title": "Bevestig je e-mailadres - Jellyfin",
|
||||
"clickBelow": "Klik op onderstaande link om je e-mailadres te bevestigen en te beginnen met Jellyfin.",
|
||||
"confirmEmail": "Bevestig e-mailadres",
|
||||
"name": "Bevestingingse-mail"
|
||||
},
|
||||
"userExpired": {
|
||||
"name": "Gebruikersverloop",
|
||||
"title": "Je account is verlopen - Jellyfin",
|
||||
"yourAccountHasExpired": "Je account is verlopen.",
|
||||
"contactTheAdmin": "Neem contact op met de beheerder voor meer info."
|
||||
},
|
||||
"userDisabled": {
|
||||
"title": "Je account is uitgeschakeld - Jellyfin",
|
||||
"name": "Gebruiker uitgeschakeld",
|
||||
"yourAccountWasDisabled": "Je account is uitgeschakeld."
|
||||
},
|
||||
"userEnabled": {
|
||||
"yourAccountWasEnabled": "Je account is opnieuw ingeschakeld.",
|
||||
"name": "Gebruiker ingeschakeld",
|
||||
"title": "Je account is opnieuw ingeschakeld - Jellyfin"
|
||||
}
|
||||
}
|
||||
77
lang/email/pt-br.json
Normal file
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Português (BR)"
|
||||
},
|
||||
"strings": {
|
||||
"ifItWasNotYou": "Se não foi você, ignore este e-mail.",
|
||||
"reason": "Razão",
|
||||
"helloUser": "Ola {username},"
|
||||
},
|
||||
"userCreated": {
|
||||
"title": "Aviso: Usuário criado",
|
||||
"aUserWasCreated": "Um usuário foi criado usando o código {code}.",
|
||||
"time": "Tempo",
|
||||
"notificationNotice": "Nota: Os emails de notificação podem ser alternados no painel do administrador.",
|
||||
"name": "Criação de usuário"
|
||||
},
|
||||
"inviteExpiry": {
|
||||
"title": "Aviso: Convite expirado",
|
||||
"inviteExpired": "Convite expirado.",
|
||||
"expiredAt": "O código {code} expirou em {time}.",
|
||||
"notificationNotice": "Nota: Os emails de notificação podem ser alternados no painel do administrador.",
|
||||
"name": "Convite Expirado"
|
||||
},
|
||||
"passwordReset": {
|
||||
"title": "Redefinir senha foi solicitada - Jellyfin",
|
||||
"someoneHasRequestedReset": "Alguém recentemente solicitou uma redefinição de senha no Jellyfin.",
|
||||
"ifItWasYou": "Se foi você, insira o PIN abaixo.",
|
||||
"codeExpiry": "O código irá expirar em {date}, ás {time}, que está em {expiresInMinutes}.",
|
||||
"pin": "PIN",
|
||||
"name": "Redefinir senha",
|
||||
"ifItWasYouLink": "Se foi você, clique no link abaixo."
|
||||
},
|
||||
"userDeleted": {
|
||||
"title": "Sua conta foi excluída - Jellyfin",
|
||||
"yourAccountWasDeleted": "Sua conta Jellyfin foi excluída.",
|
||||
"name": "Exclusão do usuário"
|
||||
},
|
||||
"inviteEmail": {
|
||||
"title": "Convite - Jellyfin",
|
||||
"hello": "Ola",
|
||||
"youHaveBeenInvited": "Você recebeu um convite para o Jellyfin.",
|
||||
"toJoin": "Para participar, clique no link abaixo.",
|
||||
"inviteExpiry": "Este convite expira em {date} às {time}, que é em {expiresInMinutes}, então seja rápido.",
|
||||
"linkButton": "Crie sua conta",
|
||||
"name": "Convide por email"
|
||||
},
|
||||
"welcomeEmail": {
|
||||
"title": "Bem vindo ao Jellyfin",
|
||||
"welcome": "Bem vindo ao Jellyfin!",
|
||||
"youCanLoginWith": "Abaixo está os detalhes para fazer o login",
|
||||
"jellyfinURL": "URL",
|
||||
"name": "Email de Boas vindas",
|
||||
"yourAccountWillExpire": "Sua conta irá expirar em {date}."
|
||||
},
|
||||
"emailConfirmation": {
|
||||
"title": "Confirme seu email - Jellyfin",
|
||||
"clickBelow": "Clique no link abaixo para confirmar seu endereço de e-mail e começar a usar o Jellyfin.",
|
||||
"confirmEmail": "Confirmar Email",
|
||||
"name": "Email de Confirmação"
|
||||
},
|
||||
"userExpired": {
|
||||
"name": "Vencimento do usuário",
|
||||
"title": "Sua conta expirou - Jellyfin",
|
||||
"yourAccountHasExpired": "Sua conta expirou.",
|
||||
"contactTheAdmin": "Entre em contato com administrador para mais informações."
|
||||
},
|
||||
"userDisabled": {
|
||||
"name": "Usuário desativado",
|
||||
"title": "Sua conta foi desativada - Jellyfin",
|
||||
"yourAccountWasDisabled": "Sua conta foi desativada."
|
||||
},
|
||||
"userEnabled": {
|
||||
"title": "Sua conta foi reativada - Jellyfin",
|
||||
"name": "Usuário ativado",
|
||||
"yourAccountWasEnabled": "Sua conta foi reativada."
|
||||
}
|
||||
}
|
||||
65
lang/email/sv-se.json
Normal file
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Svenska (SV)"
|
||||
},
|
||||
"strings": {
|
||||
"ifItWasNotYou": "Om detta inte var du, ignorera det här e-postmeddelandet.",
|
||||
"helloUser": "Hej {username},",
|
||||
"reason": "Anledning"
|
||||
},
|
||||
"userCreated": {
|
||||
"name": "Användarskapande",
|
||||
"title": "Meddelande: Användare skapad",
|
||||
"aUserWasCreated": "En användare skapades med hjälp av koden {code}.",
|
||||
"time": "Tid",
|
||||
"notificationNotice": "Observera: E-postmeddelanden om avisering kan ändras på admin-instrumentpanelen."
|
||||
},
|
||||
"inviteExpiry": {
|
||||
"name": "Utgångsdatum för inbjudan",
|
||||
"title": "Meddelande: Inbjudan har upphört att gälla",
|
||||
"inviteExpired": "Inbjudan har upphört att gälla.",
|
||||
"expiredAt": "Koden {code} upphörde att gälla {time}.",
|
||||
"notificationNotice": "Observera: Notifierings-e-postmeddelanden kan ändras på admin-instrumentpanelen."
|
||||
},
|
||||
"passwordReset": {
|
||||
"name": "Återställning av lösenord",
|
||||
"title": "Lösenordsåterställning begärd - Jellyfin",
|
||||
"someoneHasRequestedReset": "Någon har nyligen begärt en återställning av lösenordet på Jellyfin.",
|
||||
"ifItWasYou": "Om det var du, ange pinkoden nedan i prompten.",
|
||||
"codeExpiry": "Koden upphör att gälla den {date}, vid {time} UTC, vilket är om {expiresInMinutes}.",
|
||||
"pin": "Pinkod"
|
||||
},
|
||||
"userDeleted": {
|
||||
"name": "Radering av användare",
|
||||
"title": "Ditt konto raderades - Jellyfin",
|
||||
"yourAccountWasDeleted": "Ditt Jellyfin-konto raderades."
|
||||
},
|
||||
"inviteEmail": {
|
||||
"name": "Inbjudnings e-post",
|
||||
"title": "Inbjudan - Jellyfin",
|
||||
"hello": "Hej",
|
||||
"youHaveBeenInvited": "Du har blivit inbjuden till Jellyfin.",
|
||||
"toJoin": "För att gå med, följ länken nedan.",
|
||||
"inviteExpiry": "Denna inbjudan upphör att gälla den {date} vid {time}, vilket är om {expiresInMinutes}, så agera snabbt.",
|
||||
"linkButton": "Ställ in ditt konto"
|
||||
},
|
||||
"welcomeEmail": {
|
||||
"name": "Välkomst e-post",
|
||||
"title": "Välkommen till Jellyfin",
|
||||
"welcome": "Välkommen till Jellyfin!",
|
||||
"youCanLoginWith": "Du kan logga in med informationen nedan",
|
||||
"jellyfinURL": "URL"
|
||||
},
|
||||
"emailConfirmation": {
|
||||
"name": "Bekräftelse e-post",
|
||||
"title": "Bekräfta din e-postadress - Jellyfin",
|
||||
"clickBelow": "Klicka på länken nedan för att bekräfta din e-postadress och börja använda Jellyfin.",
|
||||
"confirmEmail": "Bekräfta e-postadress"
|
||||
},
|
||||
"userExpired": {
|
||||
"name": "Användarens upphörande",
|
||||
"title": "Ditt konto har gått ut - Jellyfin",
|
||||
"yourAccountHasExpired": "Ditt konto har gått ut.",
|
||||
"contactTheAdmin": "Kontakta administratören för mer information."
|
||||
}
|
||||
}
|
||||
48
lang/form/de-de.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Deutsch (DE)"
|
||||
},
|
||||
"strings": {
|
||||
"pageTitle": "Jellyfin-Konto erstellen",
|
||||
"createAccountHeader": "Konto erstellen",
|
||||
"accountDetails": "Kontodaten",
|
||||
"emailAddress": "E-Mail",
|
||||
"username": "Benutzername",
|
||||
"password": "Passwort",
|
||||
"reEnterPassword": "Passwort wiederholen",
|
||||
"reEnterPasswordInvalid": "Passwörter stimmen nicht überein.",
|
||||
"createAccountButton": "Konto erstellen",
|
||||
"passwordRequirementsHeader": "Passwortanforderungen",
|
||||
"successHeader": "Erfolgreich!",
|
||||
"successContinueButton": "Weiter",
|
||||
"confirmationRequired": "E-Mail-Bestätigung erforderlich",
|
||||
"confirmationRequiredMessage": "Bitte überprüfe dein Posteingang und bestätige deine E-Mail-Adresse.",
|
||||
"yourAccountIsValidUntil": "Dein Konto wird bis zum {date} gültig sein."
|
||||
},
|
||||
"validationStrings": {
|
||||
"length": {
|
||||
"singular": "Muss mindestens {n} Zeichen haben",
|
||||
"plural": "Muss mindestens {n} Zeichen haben"
|
||||
},
|
||||
"uppercase": {
|
||||
"singular": "Muss mindestens {n} Großbuchstaben haben",
|
||||
"plural": "Muss mindestens {n} Großbuchstaben haben"
|
||||
},
|
||||
"lowercase": {
|
||||
"singular": "Muss mindestens {n} Kleinbuchstaben haben",
|
||||
"plural": "Muss mindestens {n} Kleinbuchstaben haben"
|
||||
},
|
||||
"number": {
|
||||
"singular": "Muss mindestens {n} Zahl haben",
|
||||
"plural": "Muss mindestens {n} Zahlen haben"
|
||||
},
|
||||
"special": {
|
||||
"singular": "Muss mindestens {n} Sonderzeichen haben",
|
||||
"plural": "Muss mindestens {n} Sonderzeichen haben"
|
||||
}
|
||||
},
|
||||
"notifications": {
|
||||
"errorUserExists": "Benutzer existiert bereits.",
|
||||
"errorInvalidCode": "Ungültiger Invite-Code."
|
||||
}
|
||||
}
|
||||
48
lang/form/el-gr.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Ελληνικά (GR)"
|
||||
},
|
||||
"strings": {
|
||||
"pageTitle": "Δημιουργία λογαριασμού Jellyfin",
|
||||
"createAccountHeader": "Δημιουργία Λογαρισμού",
|
||||
"accountDetails": "Λεπτομέρειες",
|
||||
"emailAddress": "Email",
|
||||
"username": "Όνομα Χρήστη",
|
||||
"password": "Κωδικός",
|
||||
"reEnterPassword": "Επιβεβαίωση Κωδικού",
|
||||
"reEnterPasswordInvalid": "Οι κωδικοί δεν είναι ίδιοι.",
|
||||
"createAccountButton": "Δημιουργία Λογαρισμού",
|
||||
"passwordRequirementsHeader": "Απαιτήσεις Κωδικού",
|
||||
"successHeader": "Επιτυχία!",
|
||||
"successContinueButton": "Συνέχεια",
|
||||
"confirmationRequired": "Απαιτείται επιβεβαίωση Email",
|
||||
"confirmationRequiredMessage": "Παρακαλώ ελέγξτε το email σας για να επιβεβαιώσετε την διεύθυνση σας .",
|
||||
"yourAccountIsValidUntil": "Ο λογαριασμός σου θα ισχύει μέχρι {date}."
|
||||
},
|
||||
"notifications": {
|
||||
"errorUserExists": "Ο χρήστης υπάρχει ήδη.",
|
||||
"errorInvalidCode": "Άκυρος κωδικός πρόσκλησης."
|
||||
},
|
||||
"validationStrings": {
|
||||
"length": {
|
||||
"singular": "Πρέπει να περιέχει τουλάχιστον {n} χαρακτήρες",
|
||||
"plural": "Πρέπει να περιέχει τουλάχιστον {n} χαρακτήρα"
|
||||
},
|
||||
"uppercase": {
|
||||
"singular": "Πρέπει να περιέχει τουλάχιστον {n} κεφαλαίο χαρακτήρα",
|
||||
"plural": "Πρέπει να περιέχει τουλάχιστον {n} κεφαλαίους χαρακτήρες"
|
||||
},
|
||||
"lowercase": {
|
||||
"singular": "Πρέπει να περιέχει τουλάχιστον {n} πεζό χαρακτήρα",
|
||||
"plural": "Πρέπει να περιέχει τουλάχιστον {n} πεζούς χαρακτήρες"
|
||||
},
|
||||
"number": {
|
||||
"singular": "Πρέπει να περιέχει τουλάχιστον {n} αριθμό",
|
||||
"plural": "Πρέπει να περιέχει τουλάχιστον {n} αριθμούς"
|
||||
},
|
||||
"special": {
|
||||
"singular": "Πρέπει να περιέχει τουλάχιστον {n} ειδικό χαρακτήρα",
|
||||
"plural": "Πρέπει να περιέχει τουλάχιστον {n} ειδικούς χαρακτήρες"
|
||||
}
|
||||
}
|
||||
}
|
||||
5
lang/form/en-gb.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "English (GB)"
|
||||
}
|
||||
}
|
||||
@@ -15,27 +15,38 @@
|
||||
"passwordRequirementsHeader": "Password Requirements",
|
||||
"successHeader": "Success!",
|
||||
"successContinueButton": "Continue",
|
||||
"validationStrings": {
|
||||
"length": {
|
||||
"singular": "Must have at least {n} character",
|
||||
"plural": "Must have a least {n} characters"
|
||||
},
|
||||
"uppercase": {
|
||||
"singular": "Must have at least {n} uppercase character",
|
||||
"plural": "Must have at least {n} uppercase characters"
|
||||
},
|
||||
"lowercase": {
|
||||
"singular": "Must have at least {n} lowercase character",
|
||||
"plural": "Must have at least {n} lowercase characters"
|
||||
},
|
||||
"number": {
|
||||
"singular": "Must have at least {n} number",
|
||||
"plural": "Must have at least {n} numbers"
|
||||
},
|
||||
"special": {
|
||||
"singular": "Must have at least {n} special character",
|
||||
"plural": "Must have at least {n} special characters"
|
||||
}
|
||||
"confirmationRequired": "Email confirmation required",
|
||||
"confirmationRequiredMessage": "Please check your email inbox to verify your address.",
|
||||
"yourAccountIsValidUntil": "Your account will be valid until {date}.",
|
||||
"sendPIN": "Send the PIN below to the bot, then come back here to link your account."
|
||||
},
|
||||
"notifications": {
|
||||
"errorUserExists": "User already exists.",
|
||||
"errorInvalidCode": "Invalid invite code.",
|
||||
"errorTelegramVerification": "Telegram verification required.",
|
||||
"errorInvalidPIN": "Telegram PIN is invalid.",
|
||||
"telegramVerified": "Telegram account verified."
|
||||
},
|
||||
"validationStrings": {
|
||||
"length": {
|
||||
"singular": "Must have at least {n} character",
|
||||
"plural": "Must have at least {n} characters"
|
||||
},
|
||||
"uppercase": {
|
||||
"singular": "Must have at least {n} uppercase character",
|
||||
"plural": "Must have at least {n} uppercase characters"
|
||||
},
|
||||
"lowercase": {
|
||||
"singular": "Must have at least {n} lowercase character",
|
||||
"plural": "Must have at least {n} lowercase characters"
|
||||
},
|
||||
"number": {
|
||||
"singular": "Must have at least {n} number",
|
||||
"plural": "Must have at least {n} numbers"
|
||||
},
|
||||
"special": {
|
||||
"singular": "Must have at least {n} special character",
|
||||
"plural": "Must have at least {n} special characters"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
48
lang/form/es-es.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Español (ES)"
|
||||
},
|
||||
"strings": {
|
||||
"pageTitle": "Crear cuenta de Jellyfin",
|
||||
"createAccountHeader": "Crear una cuenta",
|
||||
"accountDetails": "Detalles",
|
||||
"emailAddress": "Correo electrónico",
|
||||
"username": "Nombre de usuario",
|
||||
"password": "Contraseña",
|
||||
"reEnterPassword": "Rescriba su contraseña",
|
||||
"reEnterPasswordInvalid": "Las contraseñas no son coincidentes.",
|
||||
"createAccountButton": "Crear una cuenta",
|
||||
"passwordRequirementsHeader": "Requisitos de contraseña",
|
||||
"successHeader": "¡Éxito!",
|
||||
"successContinueButton": "Continuar",
|
||||
"confirmationRequired": "Se requiere confirmación por correo electrónico",
|
||||
"confirmationRequiredMessage": "Revise la bandeja de entrada de su correo electrónico para verificar su dirección.",
|
||||
"yourAccountIsValidUntil": "Su cuenta será válida hasta el {date}."
|
||||
},
|
||||
"notifications": {
|
||||
"errorUserExists": "El usuario ya existe.",
|
||||
"errorInvalidCode": "Código de invitación no es válido."
|
||||
},
|
||||
"validationStrings": {
|
||||
"length": {
|
||||
"singular": "Debe tener al menos {n} carácter",
|
||||
"plural": "Debe tener al menos {n} caracteres"
|
||||
},
|
||||
"uppercase": {
|
||||
"singular": "Debe tener al menos {n} caracteres en mayúscula",
|
||||
"plural": "Debe tener al menos {n} caracteres en mayúscula"
|
||||
},
|
||||
"lowercase": {
|
||||
"singular": "Debe tener al menos {n} caracteres en minúscula",
|
||||
"plural": "Debe tener al menos {n} caracteres en minúscula"
|
||||
},
|
||||
"number": {
|
||||
"singular": "Debe tener al menos {n} número",
|
||||
"plural": "Debe tener al menos {n} números"
|
||||
},
|
||||
"special": {
|
||||
"singular": "Debe tener al menos {n} carácter especial",
|
||||
"plural": "Debe tener al menos {n} caracteres especiales"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Francais (FR)",
|
||||
"name": "Français (FR)",
|
||||
"author": "https://github.com/Killianbe"
|
||||
},
|
||||
"strings": {
|
||||
@@ -8,7 +8,7 @@
|
||||
"createAccountHeader": "Création du compte",
|
||||
"accountDetails": "Détails",
|
||||
"emailAddress": "Email",
|
||||
"username": "Pseudo",
|
||||
"username": "Nom d'utilisateur",
|
||||
"password": "Mot de passe",
|
||||
"reEnterPassword": "Confirmez mot de passe",
|
||||
"reEnterPasswordInvalid": "Les mots de passe ne correspondent pas.",
|
||||
@@ -16,27 +16,33 @@
|
||||
"passwordRequirementsHeader": "Mot de passe requis",
|
||||
"successHeader": "Succes!",
|
||||
"successContinueButton": "Continuer",
|
||||
"validationStrings": {
|
||||
"length": {
|
||||
"singular": "Doit avoir au moins {n} caractère",
|
||||
"plural": "Doit avoir au moins {n} caractères"
|
||||
},
|
||||
"uppercase": {
|
||||
"singular": "Doit avoir au moins {n} caractère majuscule",
|
||||
"plural": "Must have at least {n} caractères majuscules"
|
||||
},
|
||||
"lowercase": {
|
||||
"singular": "Doit avoir au moins {n} caractère minuscule",
|
||||
"plural": "Doit avoir au moins {n} caractères minuscules"
|
||||
},
|
||||
"number": {
|
||||
"singular": "Doit avoir au moins {n} nombre",
|
||||
"plural": "Doit avoir au moins {n} nombres"
|
||||
},
|
||||
"special": {
|
||||
"singular": "Doit avoir au moins {n} caractère spécial",
|
||||
"plural": "Doit avoir au moins {n} caractères spéciaux"
|
||||
}
|
||||
"confirmationRequired": "Confirmation de l'adresse e-mail requise",
|
||||
"confirmationRequiredMessage": "Veuillez vérifier votre boite de réception pour confirmer votre adresse e-mail."
|
||||
},
|
||||
"validationStrings": {
|
||||
"length": {
|
||||
"singular": "Doit avoir au moins {n} caractère",
|
||||
"plural": "Doit avoir au moins {n} caractères"
|
||||
},
|
||||
"uppercase": {
|
||||
"singular": "Doit avoir au moins {n} caractère majuscule",
|
||||
"plural": "Must have at least {n} caractères majuscules"
|
||||
},
|
||||
"lowercase": {
|
||||
"singular": "Doit avoir au moins {n} caractère minuscule",
|
||||
"plural": "Doit avoir au moins {n} caractères minuscules"
|
||||
},
|
||||
"number": {
|
||||
"singular": "Doit avoir au moins {n} nombre",
|
||||
"plural": "Doit avoir au moins {n} nombres"
|
||||
},
|
||||
"special": {
|
||||
"singular": "Doit avoir au moins {n} caractère spécial",
|
||||
"plural": "Doit avoir au moins {n} caractères spéciaux"
|
||||
}
|
||||
},
|
||||
"notifications": {
|
||||
"errorUserExists": "Utilisateur déjà existant.",
|
||||
"errorInvalidCode": "Code d’invitation non valide."
|
||||
}
|
||||
}
|
||||
|
||||
47
lang/form/id-id.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Bahasa Indonesia (ID)"
|
||||
},
|
||||
"strings": {
|
||||
"pageTitle": "Buat Akun Jellyfin",
|
||||
"createAccountHeader": "Buat Akun",
|
||||
"accountDetails": "Detail",
|
||||
"emailAddress": "Email",
|
||||
"username": "Nama pengguna",
|
||||
"password": "Sandi",
|
||||
"reEnterPassword": "Masukkan kembali sandi",
|
||||
"reEnterPasswordInvalid": "Kata sandi tidak sama.",
|
||||
"createAccountButton": "Buat Akun",
|
||||
"passwordRequirementsHeader": "Persyaratan Kata Sandi",
|
||||
"successHeader": "Sukses!",
|
||||
"successContinueButton": "Lanjut",
|
||||
"confirmationRequired": "Konfirmasi email diperlukan",
|
||||
"confirmationRequiredMessage": "Silakan periksa kotak masuk email Anda untuk memverifikasi alamat Anda."
|
||||
},
|
||||
"notifications": {
|
||||
"errorUserExists": "Pengguna sudah ada.",
|
||||
"errorInvalidCode": "Kode undangan tidak valid."
|
||||
},
|
||||
"validationStrings": {
|
||||
"length": {
|
||||
"singular": "Harus memiliki setidaknya {n} karakter",
|
||||
"plural": "Harus memiliki setidaknya {n} karakter"
|
||||
},
|
||||
"uppercase": {
|
||||
"singular": "Harus memiliki setidaknya {n} karakter huruf besar",
|
||||
"plural": "Harus memiliki setidaknya {n} karakter huruf besar"
|
||||
},
|
||||
"lowercase": {
|
||||
"singular": "Harus memiliki setidaknya {n} karakter huruf kecil",
|
||||
"plural": "Harus memiliki setidaknya {n} karakter huruf kecil"
|
||||
},
|
||||
"number": {
|
||||
"singular": "Harus memiliki setidaknya {n} nomor",
|
||||
"plural": "Harus memiliki setidaknya {n} nomor"
|
||||
},
|
||||
"special": {
|
||||
"singular": "Harus memiliki setidaknya {n} karakter khusus",
|
||||
"plural": "Harus memiliki setidaknya {n} karakter khusus"
|
||||
}
|
||||
}
|
||||
}
|
||||
47
lang/form/it-it.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Italiano (IT)"
|
||||
},
|
||||
"strings": {
|
||||
"pageTitle": "Crea Un Account Jellyfin",
|
||||
"createAccountHeader": "Crea Un Account",
|
||||
"accountDetails": "Dettagli",
|
||||
"emailAddress": "Email",
|
||||
"username": "Nome utente",
|
||||
"password": "Password",
|
||||
"reEnterPassword": "Riscrivi La Password",
|
||||
"reEnterPasswordInvalid": "Le password non sono uguali.",
|
||||
"createAccountButton": "Crea Un Account",
|
||||
"passwordRequirementsHeader": "Requisiti Password",
|
||||
"successHeader": "Successo!",
|
||||
"successContinueButton": "Continua",
|
||||
"confirmationRequired": "Richiesta la conferma Email",
|
||||
"confirmationRequiredMessage": "Controlla la tua casella email per verificare il tuo indirizzo."
|
||||
},
|
||||
"notifications": {
|
||||
"errorUserExists": "L'utente è già esistente.",
|
||||
"errorInvalidCode": "Codice di invito non valido."
|
||||
},
|
||||
"validationStrings": {
|
||||
"length": {
|
||||
"singular": "Deve avere almeno {n} caratteri",
|
||||
"plural": "Deve aveere almeno {n} caratteri"
|
||||
},
|
||||
"uppercase": {
|
||||
"singular": "Deve avere almeno {n} carattere maiuscolo",
|
||||
"plural": "Deve avere almeno {n} caratteri maiuscoli"
|
||||
},
|
||||
"lowercase": {
|
||||
"singular": "Deve avere almeno {n} carattere minuscolo",
|
||||
"plural": "Deve avere almeno {n} caratteri minuscoli"
|
||||
},
|
||||
"number": {
|
||||
"singular": "Deve avere almeno {n} numero",
|
||||
"plural": "Deve avere almeno {n} numeri"
|
||||
},
|
||||
"special": {
|
||||
"singular": "Deve avere almeno {n} carattere speciale",
|
||||
"plural": "Deve avere almeno {n} caratteri speciali"
|
||||
}
|
||||
}
|
||||
}
|
||||
48
lang/form/nl-nl.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Nederlands (NL)"
|
||||
},
|
||||
"strings": {
|
||||
"pageTitle": "Maak Jellyfin account aan",
|
||||
"createAccountHeader": "Account aanmaken",
|
||||
"accountDetails": "Details",
|
||||
"emailAddress": "E-mail",
|
||||
"username": "Gebruikersnaam",
|
||||
"password": "Wachtwoord",
|
||||
"reEnterPassword": "Bevestig wachtwoord",
|
||||
"reEnterPasswordInvalid": "Wachtwoorden komen niet overeen.",
|
||||
"createAccountButton": "Maak account aan",
|
||||
"passwordRequirementsHeader": "Wachtwoordvereisten",
|
||||
"successHeader": "Succes!",
|
||||
"successContinueButton": "Doorgaan",
|
||||
"confirmationRequired": "Bevestiging van e-mailadres verplicht",
|
||||
"confirmationRequiredMessage": "Controleer je e-mail inbox om je adres te bevestigen.",
|
||||
"yourAccountIsValidUntil": "Je account zal geldig zijn tot {date}."
|
||||
},
|
||||
"validationStrings": {
|
||||
"length": {
|
||||
"singular": "Moet ten minste {n} teken bevatten",
|
||||
"plural": "Moet ten minste {n} tekens bevatten"
|
||||
},
|
||||
"uppercase": {
|
||||
"singular": "Moet ten minste {n} hoofdletter bevatten",
|
||||
"plural": "Moet ten minste {n} hoofdletters bevatten"
|
||||
},
|
||||
"lowercase": {
|
||||
"singular": "Moet ten minste {n} kleine letter bevatten",
|
||||
"plural": "Moet ten minste {n} kleine letters bevatten"
|
||||
},
|
||||
"number": {
|
||||
"singular": "Moet ten minste {n} cijfer bevatten",
|
||||
"plural": "Moet ten minste {n} cijfers bevatten"
|
||||
},
|
||||
"special": {
|
||||
"singular": "Moet ten minste {n} bijzonder teken bevatten",
|
||||
"plural": "Moet ten minste {n} bijzondere tekens bevatten"
|
||||
}
|
||||
},
|
||||
"notifications": {
|
||||
"errorUserExists": "Gebruiker bestaat al.",
|
||||
"errorInvalidCode": "Ongeldige uitnodigingscode."
|
||||
}
|
||||
}
|
||||
48
lang/form/pt-br.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Português (BR)"
|
||||
},
|
||||
"strings": {
|
||||
"pageTitle": "Criar Conta Jellyfin",
|
||||
"createAccountHeader": "Criar Conta",
|
||||
"accountDetails": "Detalhes",
|
||||
"emailAddress": "Email",
|
||||
"username": "Nome do Usuário",
|
||||
"password": "Senha",
|
||||
"reEnterPassword": "Digite a Senha Novamente",
|
||||
"reEnterPasswordInvalid": "Senha não Coincidem. Tentar novamente.",
|
||||
"createAccountButton": "Criar Conta",
|
||||
"passwordRequirementsHeader": "Requisitos da Senha",
|
||||
"successHeader": "Sucesso!",
|
||||
"successContinueButton": "Continuar",
|
||||
"confirmationRequired": "Necessária confirmação de e-mail",
|
||||
"confirmationRequiredMessage": "Verifique sua caixa de email para finalizar o cadastro.",
|
||||
"yourAccountIsValidUntil": "Sua conta é válida até {date}."
|
||||
},
|
||||
"notifications": {
|
||||
"errorUserExists": "Esse usuário já existe.",
|
||||
"errorInvalidCode": "Código do convite invalido."
|
||||
},
|
||||
"validationStrings": {
|
||||
"length": {
|
||||
"singular": "Deve ter pelo menos {n} caractere",
|
||||
"plural": "Deve ter pelo menos {n} caracteres"
|
||||
},
|
||||
"uppercase": {
|
||||
"singular": "Deve ter pelo menos {n} caractere maiúsculo",
|
||||
"plural": "Deve ter pelo menos {n} caracteres maiúsculos"
|
||||
},
|
||||
"lowercase": {
|
||||
"singular": "Deve ter pelo menos {n} caractere minúsculo",
|
||||
"plural": "Deve ter pelo menos {n} caracteres minúsculos"
|
||||
},
|
||||
"number": {
|
||||
"singular": "Deve ter pelo menos {n} número",
|
||||
"plural": "Deve ter pelo menos {n} números"
|
||||
},
|
||||
"special": {
|
||||
"singular": "Deve ter pelo menos {n} caractere especial",
|
||||
"plural": "Deve ter pelo menos {n} caracteres especiais"
|
||||
}
|
||||
}
|
||||
}
|
||||
48
lang/form/sv-se.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Svenska (SV)"
|
||||
},
|
||||
"strings": {
|
||||
"pageTitle": "Skapa Jellyfin-konto",
|
||||
"createAccountHeader": "Skapa konto",
|
||||
"accountDetails": "Detaljer",
|
||||
"emailAddress": "E-post",
|
||||
"username": "Användarnamn",
|
||||
"password": "Lösenord",
|
||||
"reEnterPassword": "Skriv lösenordet igen",
|
||||
"reEnterPasswordInvalid": "Lösenorden är inte samma.",
|
||||
"createAccountButton": "Skapa konto",
|
||||
"passwordRequirementsHeader": "Lösenordskrav",
|
||||
"successHeader": "Lyckades!",
|
||||
"successContinueButton": "Fortsätt",
|
||||
"confirmationRequired": "E-postbekräftelse krävs",
|
||||
"confirmationRequiredMessage": "Kontrollera din e-postkorg för att verifiera din adress.",
|
||||
"yourAccountIsValidUntil": "Ditt konto är giltigt fram tills {date}."
|
||||
},
|
||||
"notifications": {
|
||||
"errorUserExists": "Användare finns redan.",
|
||||
"errorInvalidCode": "Ogiltig inbjudningskod."
|
||||
},
|
||||
"validationStrings": {
|
||||
"length": {
|
||||
"singular": "Måste ha minst {n} tecken",
|
||||
"plural": "Måste ha minst {n} tecken"
|
||||
},
|
||||
"uppercase": {
|
||||
"singular": "Måste ha minst {n} versaler",
|
||||
"plural": "Måste ha minst {n} versaler"
|
||||
},
|
||||
"lowercase": {
|
||||
"singular": "Måste ha minst {n} gemener",
|
||||
"plural": "Måste ha minst {n} gemener"
|
||||
},
|
||||
"number": {
|
||||
"singular": "Måste ha minst {n} siffra",
|
||||
"plural": "Måste ha minst {n} siffror"
|
||||
},
|
||||
"special": {
|
||||
"singular": "Måste ha minst {n} specialtecken",
|
||||
"plural": "Måste ha minst {n} specialtecken"
|
||||
}
|
||||
}
|
||||
}
|
||||
13
lang/pwreset/en-us.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "English (US)"
|
||||
},
|
||||
"strings": {
|
||||
"passwordReset": "Password reset",
|
||||
"resetFailed": "Password reset failed",
|
||||
"tryAgain": "Please try again.",
|
||||
"youCanLogin": "You can now log in with the below code as your password.",
|
||||
"youCanLoginOmbi": "You can now log in to Jellyfin & Ombi with the below code as your password.",
|
||||
"changeYourPassword": "Make sure to change your password after you log in."
|
||||
}
|
||||
}
|
||||
12
lang/pwreset/es-es.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Español (ES)"
|
||||
},
|
||||
"strings": {
|
||||
"passwordReset": "Cambiar contraseña",
|
||||
"resetFailed": "Error al cambiar contraseña",
|
||||
"tryAgain": "Por favor intente nuevamente.",
|
||||
"youCanLogin": "Ahora puedes logearte con el codigo como contraseña.",
|
||||
"changeYourPassword": "Recuerda cambiar tu contraseña luego de iniciar sesión."
|
||||
}
|
||||
}
|
||||
134
lang/setup/de-de.json
Normal file
@@ -0,0 +1,134 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Deutsch (DE)"
|
||||
},
|
||||
"strings": {
|
||||
"pageTitle": "Setup - jfa-go",
|
||||
"next": "Weiter",
|
||||
"back": "Zurück",
|
||||
"optional": "Optional",
|
||||
"serverType": "Servertyp",
|
||||
"disabled": "Deaktiviert",
|
||||
"enabled": "Aktiviert",
|
||||
"port": "Port",
|
||||
"message": "Nachricht",
|
||||
"serverAddress": "Serveradresse",
|
||||
"emailSubject": "E-Mail-Betreff",
|
||||
"URL": "URL",
|
||||
"apiKey": "API-Schlüssel"
|
||||
},
|
||||
"startPage": {
|
||||
"welcome": "Willkommen!",
|
||||
"pressStart": "Du musst einige Dinge tun, um jfa-go einzurichten. Drücke Start, um fortzufahren.",
|
||||
"httpsNotice": "Stelle sicher, dass du über HTTPS oder in einem privaten Netzwerk auf diese Seite zugreifst.",
|
||||
"start": "Start"
|
||||
},
|
||||
"endPage": {
|
||||
"finished": "Fertig!",
|
||||
"restartMessage": "Es gibt weitere Einstellungen, die du auf der Admin-Seite konfigurieren kannst. Klicke unten, um neu zu starten, dann aktualisiere die Seite.",
|
||||
"refreshPage": "Aktualisieren"
|
||||
},
|
||||
"language": {
|
||||
"title": "Sprache",
|
||||
"description": "Gemeinschaftsübersetzungen sind für die meisten Teile von jfa-go verfügbar. Du kannst unten die Standardsprachen auswählen, aber Benutzer können dies immer noch ändern, wenn sie wollen. Wenn du helfen willst zu übersetzen, melde dich bei {n} an, um anzufangen, etwas beizutragen!",
|
||||
"defaultAdminLang": "Admin Standardsprache",
|
||||
"defaultFormLang": "Kontoerstellung Standardsprache",
|
||||
"defaultEmailLang": "E-Mail Standardsprache"
|
||||
},
|
||||
"general": {
|
||||
"title": "Allgemein",
|
||||
"listenAddress": "Listening-Adresse",
|
||||
"urlBase": "URL-Basis",
|
||||
"urlBaseNotice": "Nur erforderlich, wenn ein Reverse-Proxy auf einer Subdomain verwendet wird (z. B. 'jellyf.in/accounts').",
|
||||
"lightTheme": "Hell",
|
||||
"darkTheme": "Dunkel",
|
||||
"useHTTPS": "HTTPS verwenden",
|
||||
"httpsPort": "HTTPS Port",
|
||||
"useHTTPSNotice": "Nur empfohlen, wenn du keinen Reverse-Proxy verwendest.",
|
||||
"pathToCertificate": "Pfad zum Zertifikat",
|
||||
"pathToKeyFile": "Pfad zur Schlüsseldatei"
|
||||
},
|
||||
"login": {
|
||||
"title": "Anmelden",
|
||||
"description": "Um auf die Admin-Seite zuzugreifen, musst du dich mit einer untenstehenden Methode anmelden:",
|
||||
"authorizeWithJellyfin": "Mit Jellyfin/Emby autorisieren: Anmeldedaten werden mit Jellyfin geteilt, was mehrere Benutzer ermöglicht.",
|
||||
"authorizeManual": "Benutzername und Passwort: Lege Benutzername und Passwort manuell fest.",
|
||||
"adminOnly": "Nur Admin-Benutzer (empfohlen)",
|
||||
"emailNotice": "Deine E-Mail-Adresse kann verwendet werden, um Benachrichtigungen zu erhalten."
|
||||
},
|
||||
"jellyfinEmby": {
|
||||
"title": "Jellyfin/Emby",
|
||||
"description": "Ein Admin-Konto ist erforderlich, weil die API keine Benutzererstellung unter Verwendung eines API-Schlüssels erlaubt. Du solltest ein separates Konto erstellen und 'Dieser Benutzer kann den Server managen' aktivieren. Du kannst alles andere deaktivieren. Ist das erledigt, gib die Anmeldedaten hier ein.",
|
||||
"embyNotice": "Emby-Unterstützung ist begrenzt und unterstützt keine Passwortzurücksetzung.",
|
||||
"internal": "Intern",
|
||||
"external": "Extern",
|
||||
"replaceJellyfin": "Servername",
|
||||
"replaceJellyfinNotice": "Wenn angegeben, ersetzt dies alle Vorkommen von 'Jellyfin' in der App.",
|
||||
"addressExternalNotice": "Leer lassen, um die selbe Adresse zu verwenden.",
|
||||
"testConnection": "Verbindung testen"
|
||||
},
|
||||
"ombi": {
|
||||
"title": "Ombi",
|
||||
"description": "Durch den Anschluss an Ombi wird sowohl ein Jellyfin-Konto als auch ein Ombi-Konto erstellt, wenn ein Benutzer durch jfa-go beitritt. Nachdem das Setup abgeschlossen ist, gehe zu den Einstellungen, um ein Standardprofil für neue Ombi-Benutzer festzulegen.",
|
||||
"apiKeyNotice": "Finde dies in der ersten Registerkarte der Ombi-Einstellungen."
|
||||
},
|
||||
"email": {
|
||||
"title": "E-Mail",
|
||||
"description": "jfa-go kann Passwortzurücksetzung-PINs und verschiedene Benachrichtigungen per E-Mail senden. Du kannst eine Verbindung zu einem SMTP-Server herstellen, oder die {n} API verwenden.",
|
||||
"method": "Versandmethode",
|
||||
"useEmailAsUsername": "E-Mail-Adresse als Benutzernamen verwenden",
|
||||
"useEmailAsUsernameNotice": "Wenn aktiviert, werden sich neue Benutzer bei Jellyfin/Emby mit ihrer E-Mail-Adresse anstatt eines Benutzernamens anmelden.",
|
||||
"fromAddress": "Absenderadresse",
|
||||
"senderName": "Absendername",
|
||||
"dateFormat": "Datumsformat",
|
||||
"dateFormatNotice": "Datum folgt dem strftime-Format. Für weitere Informationen, besuche {n}.",
|
||||
"encryption": "Verschlüsselung",
|
||||
"mailgunApiURL": "API-URL"
|
||||
},
|
||||
"notifications": {
|
||||
"title": "Benachrichtigungen",
|
||||
"description": "Wenn aktiviert, kannst du (pro Invite) wählen, eine E-Mail zu erhalten, wenn ein Invite abläuft oder ein Benutzer erstellt wird. Wenn du nicht die Jellyfin-Login-Methode gewählt hast, stelle sicher, dass du deine E-Mail-Adresse angegeben hast."
|
||||
},
|
||||
"welcomeEmails": {
|
||||
"title": "Willkommens-E-Mails",
|
||||
"description": "Wenn aktiviert, wird eine E-Mail an neue Benutzer gesendet mit der Jellyfin-/Emby-URL und ihrem Benutzername."
|
||||
},
|
||||
"inviteEmails": {
|
||||
"title": "Einladungs-E-Mails",
|
||||
"description": "Wenn aktiviert, kannst du Invites direkt an die E-Mail-Adresse eines Benutzers schicken. Weil du möglicherweise einen Reverse-Proxy verwendest, musst du die URL angeben, von welcher auf Invites zugegriffen wird. Schreibe deine URL-Basis, und füge '/invite' hinzu."
|
||||
},
|
||||
"passwordResets": {
|
||||
"title": "Passwortzurücksetzungen",
|
||||
"description": "Wenn ein Benutzer versucht sein Passwort zurückzusetzen, erstellt Jellyfin eine Datei namens 'passwordreset-*.json', welche eine PIN enthält. jfa-go liest die Datei und sendet die PIN an den Benutzer.",
|
||||
"pathToJellyfin": "Pfad zum Jellyfin-Konfigurationsverzeichnis",
|
||||
"pathToJellyfinNotice": "Wenn du nicht weißt, wo das ist, versuche dein Passwort in Jellyfin zurückzusetzen. Ein Popup mit '<Pfad zu Jellyfin>/passwordreset-*.json' wird angezeigt werden."
|
||||
},
|
||||
"passwordValidation": {
|
||||
"title": "Passwortüberprüfung",
|
||||
"description": "Wenn aktiviert, wird eine Reihe von Passwortanforderungen, wie z. B. Mindestlänge, Groß-/Kleinbuchstaben, usw., auf der Kontoerstellungsseite angezeigt.",
|
||||
"length": "Länge",
|
||||
"uppercase": "Großbuchstaben",
|
||||
"lowercase": "Kleinbuchstaben",
|
||||
"numbers": "Zahlen",
|
||||
"special": "Sonderzeichen (%, *, usw.)"
|
||||
},
|
||||
"helpMessages": {
|
||||
"title": "Hilfenachrichten",
|
||||
"description": "Diese Nachrichten werden auf der Kontoerstellungsseite und in einigen E-Mails angezeigt.",
|
||||
"contactMessage": "Kontaktnachricht",
|
||||
"contactMessageNotice": "Wird am Ende jeder außer der Admin-Seite angezeigt.",
|
||||
"helpMessage": "Hilfenachricht",
|
||||
"helpMessageNotice": "Wird auf der Kontoerstellungsseite angezeigt.",
|
||||
"successMessage": "Erfolgsnachricht",
|
||||
"successMessageNotice": "Wird angezeigt, wenn ein Benutzer sein Konto erstellt.",
|
||||
"emailMessage": "E-Mailnachricht",
|
||||
"emailMessageNotice": "Wird am Ende von E-Mails angezeigt."
|
||||
},
|
||||
"updates": {
|
||||
"updateChannel": "Aktualisierungskanal",
|
||||
"unstable": "Unstable",
|
||||
"stable": "Stable",
|
||||
"title": "Aktualisierungen",
|
||||
"description": "Aktiviere, um informiert zu werden, wenn neue Aktualisierungen verfügbar sind. jfa-go wird {n} alle 30 Minuten überprüfen. Keine IP-Adressen oder personenbezogene Daten werden gesammelt."
|
||||
}
|
||||
}
|
||||
134
lang/setup/el-gr.json
Normal file
@@ -0,0 +1,134 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Ελληνικά (GR)"
|
||||
},
|
||||
"strings": {
|
||||
"pageTitle": "Ρύθμιση - jfa-go",
|
||||
"next": "Επόμενο",
|
||||
"back": "Πίσω",
|
||||
"optional": "Προαιρετικό",
|
||||
"serverType": "Τύπος Server",
|
||||
"disabled": "Απενεργοποιημένο",
|
||||
"enabled": "Ενεργοποιημένο",
|
||||
"port": "Θύρα",
|
||||
"message": "Μήνυμα",
|
||||
"serverAddress": "Διεύθυνση Server",
|
||||
"emailSubject": "Θέμα Email",
|
||||
"URL": "URL",
|
||||
"apiKey": "Κλειδί API"
|
||||
},
|
||||
"startPage": {
|
||||
"welcome": "Καλωσήρθατε!",
|
||||
"pressStart": "Θα χρειαστεί να κάνετε μερικά πράγματα για να ρυθμίσετε το jfa-go. Πατήστε έναρξη για να συνεχίσετε.",
|
||||
"httpsNotice": "Βεβαιωθείτε ότι έχετε πρόσβαση σε αυτήν τη σελίδα μέσω HTTPS ή σε ιδιωτικό δίκτυο.",
|
||||
"start": "Έναρξη"
|
||||
},
|
||||
"endPage": {
|
||||
"finished": "Τέλος!",
|
||||
"restartMessage": "Υπάρχουν περισσότερες ρυθμίσεις που μπορείτε να διαμορφώσετε στη σελίδα διαχειριστή. Κάντε κλικ παρακάτω για επανεκκίνηση και στη συνέχεια ανανεώστε τη σελίδα.",
|
||||
"refreshPage": "Ανανέωση"
|
||||
},
|
||||
"language": {
|
||||
"title": "Γλώσσα",
|
||||
"description": "Οι μεταφράσεις κοινότητας είναι διαθέσιμες για τα περισσότερα μέρη του jfa-go. Μπορείτε να επιλέξετε τις προεπιλεγμένες γλώσσες παρακάτω, αλλά οι χρήστες μπορούν να τις αλλάξουν αν το επιθυμούν. Αν θέλετε να βοηθήσετε στη μετάφραση, εγγραφείτε στο {n} για να ξεκινήσετε να συνεισφέρετε!",
|
||||
"defaultAdminLang": "Προεπιλεγμένη γλώσσα διαχειριστή",
|
||||
"defaultFormLang": "Προεπιλεγμένη γλώσσα δημιουργίας λογαριασμού",
|
||||
"defaultEmailLang": "Προεπιλεγμένη γλώσσα email"
|
||||
},
|
||||
"general": {
|
||||
"title": "Γενικά",
|
||||
"listenAddress": "Διεύθυνση Παρακολούθησης",
|
||||
"urlBase": "URL Base",
|
||||
"urlBaseNotice": "Απαιτείται μόνο εάν χρησιμοποιείτε reverse proxy σε ένα subdomain (π.χ. «jellyf.in/accounts»).",
|
||||
"lightTheme": "Ανοιχτό",
|
||||
"darkTheme": "Σκούρο",
|
||||
"useHTTPS": "Χρήση HTTPS",
|
||||
"httpsPort": "Θύρα HTTPS",
|
||||
"useHTTPSNotice": "Συνιστάται μόνο εάν δεν χρησιμοποιείτε reverse proxy.",
|
||||
"pathToCertificate": "Διαδρομή πιστοποιητικού",
|
||||
"pathToKeyFile": "Διαδρομή αρχείου κλειδιού"
|
||||
},
|
||||
"login": {
|
||||
"title": "Σύνδεση",
|
||||
"description": "Για να αποκτήσετε πρόσβαση στη σελίδα διαχειριστή, πρέπει να συνδεθείτε με μια απο τις παρακάτω μεθόδους:",
|
||||
"authorizeWithJellyfin": "Εξουσιοδότηση με Jellyfin / Emby: Τα στοιχεία σύνδεσης κοινοποιούνται στο Jellyfin, το οποίο επιτρέπει πολλαπλούς χρήστες.",
|
||||
"authorizeManual": "Όνομα χρήστη και κωδικός πρόσβασης: Ορίστε μη αυτόματα το όνομα χρήστη και τον κωδικό πρόσβασης.",
|
||||
"adminOnly": "Μόνο διαχειριστές (συνιστάται)",
|
||||
"emailNotice": "Η διεύθυνση email σας μπορεί να χρησιμοποιηθεί για τη λήψη ειδοποιήσεων."
|
||||
},
|
||||
"jellyfinEmby": {
|
||||
"title": "Jellyfin/Emby",
|
||||
"description": "Απαιτείται λογαριασμός διαχειριστή επειδή το API δεν επιτρέπει τη δημιουργία χρηστών χρησιμοποιώντας ένα κλειδί API. Πρέπει να δημιουργήσετε έναν ξεχωριστό λογαριασμό και να επιλέξετε \"Να επιτρέπεται σε αυτόν τον χρήστη να διαχειρίζεται τον server\". Μπορείτε να απενεργοποιήσετε τα υπόλοιπα. Μόλις τελειώσετε, εισαγάγετε τα στοιχεία σύνδεσης εδώ.",
|
||||
"embyNotice": "Η υποστήριξη Emby είναι περιορισμένη και δεν υποστηρίζει επαναφορά κωδικού πρόσβασης.",
|
||||
"internal": "Εσωτερικός",
|
||||
"external": "Εξωτερικός",
|
||||
"replaceJellyfin": "Όνομα Server",
|
||||
"replaceJellyfinNotice": "Εάν δοθεί, αυτό θα αντικαταστήσει οποιαδήποτε εμφάνιση του «Jellyfin» στην εφαρμογή.",
|
||||
"addressExternalNotice": "Αφήστε κενό για να χρησιμοποιήσετε την ίδια διεύθυνση.",
|
||||
"testConnection": "Δοκιμή Σύνδεσης"
|
||||
},
|
||||
"ombi": {
|
||||
"title": "Ombi",
|
||||
"description": "Με τη σύνδεση στο Ombi, θα δημιουργηθεί ένας λογαριασμός Jellyfin και Ombi όταν ένας χρήστης συνδεθεί μέσω του jfa-go. Αφού ολοκληρώσετε τη ρύθμιση, μεταβείτε στις Ρυθμίσεις για να ορίσετε ένα προεπιλεγμένο προφίλ για νέους χρήστες ombi.",
|
||||
"apiKeyNotice": "Βρείτε το στην πρώτη καρτέλα των ρυθμίσεων Ombi."
|
||||
},
|
||||
"email": {
|
||||
"title": "Email",
|
||||
"description": "Το jfa-go μπορεί να στείλει PIN επαναφοράς κωδικού πρόσβασης και διάφορες ειδοποιήσεις μέσω email. Μπορείτε να συνδεθείτε σε έναν διακομιστή SMTP ή να χρησιμοποιήσετε το {n} API.",
|
||||
"method": "Μέθοδος αποστολής",
|
||||
"useEmailAsUsername": "Χρησιμοποιήστε τις διευθύνσεις email ως όνομα χρήστη",
|
||||
"useEmailAsUsernameNotice": "Εάν ενεργοποιηθεί, οι νέοι χρήστες θα συνδεθούν στο Jellyfin / Emby με τη διεύθυνση ηλεκτρονικού ταχυδρομείου τους αντί για το όνομα χρήστη.",
|
||||
"fromAddress": "Από τη διεύθυνση",
|
||||
"senderName": "Ονομα αποστολέα",
|
||||
"dateFormat": "Μορφή ημερομηνίας",
|
||||
"dateFormatNotice": "Η ημερομηνία ακολουθεί τη μορφή strftime. Για περισσότερες πληροφορίες, επισκεφτείτε το {n}.",
|
||||
"encryption": "Κρυπτογράφηση",
|
||||
"mailgunApiURL": "Διεύθυνση API"
|
||||
},
|
||||
"notifications": {
|
||||
"title": "Ειδοποιήσεις",
|
||||
"description": "Εάν είναι ενεργοποιημένη, μπορείτε να επιλέξετε (ανά πρόσκληση) για να λάβετε ένα email όταν λήξει μια πρόσκληση ή δημιουργηθεί ένας χρήστης. Εάν δεν επιλέξατε τη μέθοδο σύνδεσης Jellyfin, βεβαιωθείτε ότι δώσατε τη διεύθυνση email σας."
|
||||
},
|
||||
"welcomeEmails": {
|
||||
"title": "Emails καλωσορίσματος",
|
||||
"description": "Εάν είναι ενεργοποιημένο, ένα email θα σταλεί σε νέους χρήστες με το URL του Jellyfin / Emby και το όνομα χρήστη τους."
|
||||
},
|
||||
"inviteEmails": {
|
||||
"title": "Emails πρόσκλησης",
|
||||
"description": "Εάν είναι ενεργοποιημένη, μπορείτε να στείλετε προσκλήσεις απευθείας στη διεύθυνση email ενός χρήστη. Επειδή ενδέχεται να χρησιμοποιείτε reverse proxy, πρέπει να παρέχετε το URL απο όπου θα συνδεθούν. Γράψτε τη βάση URL και προσθέστε «/invite»."
|
||||
},
|
||||
"passwordResets": {
|
||||
"title": "Επαναφορά κωδικών πρόσβασης",
|
||||
"description": "Όταν ένας χρήστης προσπαθεί να επαναφέρει τον κωδικό πρόσβασής του, το Jellyfin δημιουργεί ένα αρχείο με το όνομα 'passwordreset - *. json' το οποίο περιέχει ένα PIN. Το jfa-go διαβάζει το αρχείο και στέλνει το PIN στον χρήστη.",
|
||||
"pathToJellyfin": "Διαδρομή προς τον φάκελο διαμόρφωσης Jellyfin",
|
||||
"pathToJellyfinNotice": "Εάν δεν ξέρετε πού βρίσκεται, δοκιμάστε να επαναφέρετε τον κωδικό πρόσβασής σας στο Jellyfin. Θα εμφανιστεί ένα αναδυόμενο παράθυρο με το <<path to jellyfin> / passwordreset - *. json '."
|
||||
},
|
||||
"passwordValidation": {
|
||||
"title": "Επικύρωση κωδικού πρόσβασης",
|
||||
"description": "Εάν είναι ενεργοποιημένο, ένα σύνολο απαιτήσεων κωδικού πρόσβασης θα εμφανίζεται στη σελίδα δημιουργίας λογαριασμού, όπως ελάχιστο μήκος, κεφαλαίοι / πεζοί χαρακτήρες κ.λπ.",
|
||||
"length": "Μήκος",
|
||||
"uppercase": "Κεφαλαίοι χαρακτήρες",
|
||||
"lowercase": "Πεζοί χαρακτήρες",
|
||||
"numbers": "Αριθμοί",
|
||||
"special": "Ειδικοί χαρακτήρες (%, * κ.λπ.)"
|
||||
},
|
||||
"helpMessages": {
|
||||
"title": "Μηνύματα βοήθειας",
|
||||
"description": "Αυτά τα μηνύματα θα εμφανίζονται στη σελίδα δημιουργίας λογαριασμού και σε ορισμένα email.",
|
||||
"contactMessage": "Μήνυμα επικοινωνίας",
|
||||
"contactMessageNotice": "Εμφανίζεται στο κάτω μέρος όλων των σελίδων εκτός από του διαχειριστή.",
|
||||
"helpMessage": "Μήνυμα βοήθειας",
|
||||
"helpMessageNotice": "Εμφανίζεται στη σελίδα δημιουργίας λογαριασμού.",
|
||||
"successMessage": "Μήνυμα επιτυχίας",
|
||||
"successMessageNotice": "Εμφανίζεται όταν ένας χρήστης δημιουργεί τον λογαριασμό του.",
|
||||
"emailMessage": "Μήνυμα Email",
|
||||
"emailMessageNotice": "Εμφανίζεται στο κάτω μέρος των email."
|
||||
},
|
||||
"updates": {
|
||||
"title": "Ενημερώσεις",
|
||||
"description": "Ενεργοποίηση ειδοποίησης όταν είναι διαθέσιμες νέες ενημερώσεις. Το jfa-go θα ελέγχει {n} κάθε 30 λεπτά. Δεν συλλέγονται IP ή προσωπικές πληροφορίες.",
|
||||
"updateChannel": "Κανάλι Ενημερώσεων",
|
||||
"stable": "Σταθερό",
|
||||
"unstable": "Ασταθές"
|
||||
}
|
||||
}
|
||||
5
lang/setup/en-gb.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "English (GB)"
|
||||
}
|
||||
}
|
||||
137
lang/setup/en-us.json
Normal file
@@ -0,0 +1,137 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "English (US)"
|
||||
},
|
||||
"strings": {
|
||||
"pageTitle": "Setup - jfa-go",
|
||||
"next": "Next",
|
||||
"back": "Back",
|
||||
"optional": "Optional",
|
||||
"serverType": "Server Type",
|
||||
"disabled": "Disabled",
|
||||
"enabled": "Enabled",
|
||||
"port": "Port",
|
||||
"message": "Message",
|
||||
"serverAddress": "Server Address",
|
||||
"emailSubject": "Email Subject",
|
||||
"URL": "URL",
|
||||
"apiKey": "API Key"
|
||||
},
|
||||
"startPage": {
|
||||
"welcome": "Welcome!",
|
||||
"pressStart": "You'll need to do a few things to set up jfa-go. Press start to continue.",
|
||||
"httpsNotice": "Make sure you're accessing this page via HTTPS or on a private network.",
|
||||
"start": "Start"
|
||||
},
|
||||
"endPage": {
|
||||
"finished": "Finished!",
|
||||
"restartMessage": "There are more settings you can configure on the admin page. Click below to restart, then refresh the page.",
|
||||
"refreshPage": "Refresh"
|
||||
},
|
||||
"language": {
|
||||
"title": "Language",
|
||||
"description": "Community translations are available for most parts of jfa-go. You can choose the default languages below, but users can still change it if they wish. If you want to help translate, sign up to {n} to start contributing!",
|
||||
"defaultAdminLang": "Default admin language",
|
||||
"defaultFormLang": "Default account creation language",
|
||||
"defaultEmailLang": "Default email language"
|
||||
},
|
||||
"general": {
|
||||
"title": "General",
|
||||
"listenAddress": "Listen Address",
|
||||
"urlBase": "URL Base",
|
||||
"urlBaseNotice": "Only needed if using a reverse proxy on a subdomain (e.g 'jellyf.in/accounts').",
|
||||
"lightTheme": "Light",
|
||||
"darkTheme": "Dark",
|
||||
"useHTTPS": "Use HTTPS",
|
||||
"httpsPort": "HTTPS Port",
|
||||
"useHTTPSNotice": "Only recommended if you aren't using a reverse proxy.",
|
||||
"pathToCertificate": "Path to certificate",
|
||||
"pathToKeyFile": "Path to key file"
|
||||
},
|
||||
"updates": {
|
||||
"title": "Updates",
|
||||
"description": "Enable to be notified when new updates are available. jfa-go will check {n} every 30 minutes. No IPs or personally identifiable information are collected.",
|
||||
"updateChannel": "Update Channel",
|
||||
"stable": "Stable",
|
||||
"unstable": "Unstable"
|
||||
},
|
||||
"login": {
|
||||
"title": "Login",
|
||||
"description": "To access the admin page, you need to login with a method below:",
|
||||
"authorizeWithJellyfin": "Authorize with Jellyfin/Emby: Login details are shared with Jellyfin, which allows for multiple users.",
|
||||
"authorizeManual": "Username and Password: Manually set the username and password.",
|
||||
"adminOnly": "Admin users only (recommended)",
|
||||
"emailNotice": "Your email address can be used to receive notifications."
|
||||
},
|
||||
"jellyfinEmby": {
|
||||
"title": "Jellyfin/Emby",
|
||||
"description": "An admin account is needed because the API does not allow user creation using an API key. You should create a separate account and check 'Allow this user to manage the server'. You can disable everything else. Once done, enter the login details here.",
|
||||
"embyNotice": "Emby support is limited and does not support password resets.",
|
||||
"internal": "Internal",
|
||||
"external": "External",
|
||||
"replaceJellyfin": "Server name",
|
||||
"replaceJellyfinNotice": "If given, this will replace any occurrence of 'Jellyfin' in the app.",
|
||||
"addressExternalNotice": "Leave blank to use the same address.",
|
||||
"testConnection": "Test Connection"
|
||||
},
|
||||
"ombi": {
|
||||
"title": "Ombi",
|
||||
"description": "By connecting to Ombi, both a Jellyfin and Ombi account will be created when a user joins through jfa-go. After setup is finished, go to Settings to set a default profile for new ombi users.",
|
||||
"apiKeyNotice": "Find this in the first tab of Ombi settings."
|
||||
},
|
||||
"email": {
|
||||
"title": "Email",
|
||||
"description": "jfa-go can send password reset PINs and various notifications through email. You can connect to an SMTP server, or use the {n} API.",
|
||||
"method": "Sending method",
|
||||
"useEmailAsUsername": "Use email addresses as username",
|
||||
"useEmailAsUsernameNotice": "If enabled, new users will login to Jellyfin/Emby with their email address instead of a username.",
|
||||
"fromAddress": "From Address",
|
||||
"senderName": "Sender Name",
|
||||
"dateFormat": "Date Format",
|
||||
"dateFormatNotice": "Date follows the strftime format. For more info, visit {n}.",
|
||||
"encryption": "Encryption",
|
||||
"mailgunApiURL": "API URL"
|
||||
},
|
||||
"notifications": {
|
||||
"title": "Notifications",
|
||||
"description": "If enabled, you can choose (per invite) to receive an email when an invite expires, or a user is created. If you didn't choose the Jellyfin login method, make sure you provided your email address."
|
||||
},
|
||||
"welcomeEmails": {
|
||||
"title": "Welcome emails",
|
||||
"description": "If enabled, an email will be sent to new users with the Jellyfin/Emby URL and their username."
|
||||
},
|
||||
"inviteEmails": {
|
||||
"title": "Invite Emails",
|
||||
"description": "If enabled, you can send invites directly to a user's email address. Because you might be using a reverse proxy, you need to provide the URL invites are accessed from. Write your URL Base, and append '/invite'."
|
||||
},
|
||||
"passwordResets": {
|
||||
"title": "Password Resets",
|
||||
"description": "When a user tries to reset their password, Jellyfin creates a file named 'passwordreset-*.json' which contains a PIN. jfa-go reads the file and sends the PIN to the user.",
|
||||
"pathToJellyfin": "Path to Jellyfin configuration directory",
|
||||
"pathToJellyfinNotice": "If you don't know where this is, try resetting your password in Jellyfin. A popup with '<path to jellyfin>/passwordreset-*.json' will appear.",
|
||||
"resetLinks": "Send a link instead of a PIN",
|
||||
"resetLinksNotice": "If Ombi integration is enabled, use this to sync Jellyfin password resets with Ombi.",
|
||||
"resetLinksLanguage": "Default reset link language"
|
||||
},
|
||||
"passwordValidation": {
|
||||
"title": "Password Validation",
|
||||
"description": "If enabled, a set of password requirements will show on the account creation page, such as minimum length, uppercase/lowercase characters, etc.",
|
||||
"length": "Length",
|
||||
"uppercase": "Uppercase characters",
|
||||
"lowercase": "Lowercase characters",
|
||||
"numbers": "Numbers",
|
||||
"special": "Special characters (%, *, etc.)"
|
||||
},
|
||||
"helpMessages": {
|
||||
"title": "Help Messages",
|
||||
"description": "These messages will display in the account creation page and in some emails.",
|
||||
"contactMessage": "Contact Message",
|
||||
"contactMessageNotice": "Displays at the bottom of all pages except admin.",
|
||||
"helpMessage": "Help Message",
|
||||
"helpMessageNotice": "Displays on the account creation page.",
|
||||
"successMessage": "Success Message",
|
||||
"successMessageNotice": "Displays when a user creates their account.",
|
||||
"emailMessage": "Email Message",
|
||||
"emailMessageNotice": "Displays at the bottom of emails."
|
||||
}
|
||||
}
|
||||
134
lang/setup/es-es.json
Normal file
@@ -0,0 +1,134 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Español(ES)"
|
||||
},
|
||||
"strings": {
|
||||
"pageTitle": "Configuración - jfa-go",
|
||||
"next": "Siguiente",
|
||||
"back": "Volver",
|
||||
"optional": "Opcional",
|
||||
"serverType": "Tipo de servidor",
|
||||
"disabled": "Desactivado",
|
||||
"enabled": "Activado",
|
||||
"port": "Puerto",
|
||||
"message": "Mensaje",
|
||||
"serverAddress": "Dirección del servidor",
|
||||
"emailSubject": "Asunto",
|
||||
"URL": "URL",
|
||||
"apiKey": "Llave de autorización (API)"
|
||||
},
|
||||
"startPage": {
|
||||
"welcome": "¡Bienvenido!",
|
||||
"pressStart": "Deberá hacer algunas cosas para configurar jfa-go. Presione comenzar para continuar.",
|
||||
"httpsNotice": "Asegúrese de acceder a esta página a través de HTTPS o bien desde una red privada.",
|
||||
"start": "Empezar"
|
||||
},
|
||||
"endPage": {
|
||||
"finished": "¡Terminado!",
|
||||
"restartMessage": "Hay más opciones que puede configurar en la página de administración. Haga clic a continuación para reiniciar, luego actualice la página.",
|
||||
"refreshPage": "Actualizar"
|
||||
},
|
||||
"language": {
|
||||
"title": "Lenguaje",
|
||||
"description": "Las traducciones de la comunidad están disponibles para la mayor parte de jfa-go. Puede elegir los idiomas predeterminados a continuación, pero los usuarios aún pueden cambiarlo si lo desean. Si quieres ayudar a traducir, regístrate en {n} para empezar a contribuir!",
|
||||
"defaultAdminLang": "Idioma de administrador predeterminado",
|
||||
"defaultFormLang": "Idioma de creación de cuenta predeterminado",
|
||||
"defaultEmailLang": "Idioma de correo electrónico predeterminado"
|
||||
},
|
||||
"general": {
|
||||
"title": "General",
|
||||
"listenAddress": "Dirección de recibidor (Listen Address)",
|
||||
"urlBase": "Base de URL",
|
||||
"urlBaseNotice": "Solo es necesario si se usa un proxy inverso en un subdominio (por ejemplo, 'jellyf.in/accounts').",
|
||||
"lightTheme": "Claro",
|
||||
"darkTheme": "Oscuro",
|
||||
"useHTTPS": "Usar HTTPS (Conexión segura SSL)",
|
||||
"httpsPort": "Puerto HTTPS",
|
||||
"useHTTPSNotice": "Solo se recomienda si no está utilizando un proxy inverso.",
|
||||
"pathToCertificate": "Ruta al certificado",
|
||||
"pathToKeyFile": "Ruta al archivo de claves"
|
||||
},
|
||||
"updates": {
|
||||
"title": "Actualizaciones",
|
||||
"description": "Habilite para recibir notificaciones cuando haya nuevas actualizaciones disponibles. jfa-go comprobará {n} cada 30 minutos. No se recopilan IP ni información de identificación personal.",
|
||||
"updateChannel": "Actualizar canal",
|
||||
"stable": "Estable",
|
||||
"unstable": "Inestable"
|
||||
},
|
||||
"login": {
|
||||
"title": "Iniciar sesión",
|
||||
"description": "Para acceder a la página de administración, debe iniciar sesión con un método a continuación:",
|
||||
"authorizeWithJellyfin": "Autorizar con Jellyfin/Emby: los detalles de inicio de sesión se comparten con Jellyfin, lo que permite a varios usuarios.",
|
||||
"authorizeManual": "Nombre de usuario y contraseña: establezca manualmente el nombre de usuario y la contraseña.",
|
||||
"adminOnly": "Solo usuarios administradores (recomendado)",
|
||||
"emailNotice": "Su dirección de correo electrónico se puede utilizar para recibir notificaciones."
|
||||
},
|
||||
"jellyfinEmby": {
|
||||
"title": "Jellyfin/Emby",
|
||||
"description": "Se necesita una cuenta de administrador porque la API no permite la creación de usuarios mediante una clave de API. Debe crear una cuenta separada y marcar 'Permitir que este usuario administre el servidor'. Puede desactivar todo lo demás. Una vez hecho esto, ingrese los detalles de inicio de sesión aquí.",
|
||||
"embyNotice": "El soporte de Emby es limitado y no admite el restablecimiento de contraseñas.",
|
||||
"internal": "Interno",
|
||||
"external": "Externo",
|
||||
"replaceJellyfin": "Nombre del servidor",
|
||||
"replaceJellyfinNotice": "Si se proporciona, reemplazará cualquier aparición de 'Jellyfin' en la aplicación.",
|
||||
"addressExternalNotice": "Déjelo en blanco para usar la misma dirección.",
|
||||
"testConnection": "Probar conexión"
|
||||
},
|
||||
"ombi": {
|
||||
"title": "Ombi.",
|
||||
"description": "Al conectarse a Ombi, se creará una cuenta de Jellyfin y Ombi cuando un usuario se una a través de jfa-go. Una vez finalizada la configuración, vaya a Configuración para establecer un perfil predeterminado para los nuevos usuarios de ombi.",
|
||||
"apiKeyNotice": "Encuentra esto en la primera pestaña de la configuración de Ombi."
|
||||
},
|
||||
"email": {
|
||||
"title": "Correo electrónico",
|
||||
"description": "jfa-go puede enviar PIN de restablecimiento de contraseña y varias notificaciones por correo electrónico. Puede conectarse a un servidor SMTP o utilizar la {n} API.",
|
||||
"method": "Método de envío",
|
||||
"useEmailAsUsername": "Utilice direcciones de correo electrónico como nombre de usuario",
|
||||
"useEmailAsUsernameNotice": "Si está habilitado, los nuevos usuarios iniciarán sesión en Jellyfin / Emby con su dirección de correo electrónico en lugar de un nombre de usuario.",
|
||||
"fromAddress": "Dirección de envío",
|
||||
"senderName": "Nombre del remitente",
|
||||
"dateFormat": "Formato de fecha",
|
||||
"dateFormatNotice": "La fecha sigue el formato strftime. Para obtener más información, visite {n}.",
|
||||
"encryption": "Cifrado",
|
||||
"mailgunApiURL": "URL de API"
|
||||
},
|
||||
"notifications": {
|
||||
"title": "Notificaciones",
|
||||
"description": "Si está habilitado, puede elegir (por invitación) recibir un correo electrónico cuando una invitación caduque o se cree un usuario. Si no eligió el método de inicio de sesión de Jellyfin, asegúrese de proporcionar su dirección de correo electrónico."
|
||||
},
|
||||
"welcomeEmails": {
|
||||
"title": "Correos de bienvenida",
|
||||
"description": "Si está habilitado, se enviará un correo electrónico a los nuevos usuarios con la URL de Jellyfin/Emby y su nombre de usuario."
|
||||
},
|
||||
"inviteEmails": {
|
||||
"title": "Correos de invitación",
|
||||
"description": "Si está habilitado, puede enviar invitaciones directamente a la dirección de correo electrónico de un usuario. Debido a que es posible que esté utilizando un proxy inverso, debe proporcionar la URL desde la que se accede a las invitaciones. Escriba su base de URL y agregue '/ invite'."
|
||||
},
|
||||
"passwordResets": {
|
||||
"title": "Restablecimiento de contraseña",
|
||||
"description": "Cuando un usuario intenta restablecer su contraseña, Jellyfin crea un archivo llamado 'passwordreset - *. Json' que contiene un PIN. jfa-go lee el archivo y envía el PIN al usuario.",
|
||||
"pathToJellyfin": "Ruta al directorio de configuración de Jellyfin",
|
||||
"pathToJellyfinNotice": "Si no sabe dónde está, intente restablecer su contraseña en Jellyfin. Aparecerá una ventana emergente con '<ruta a jellyfin>/passwordreset-. Json'."
|
||||
},
|
||||
"passwordValidation": {
|
||||
"title": "Validación de contraseña",
|
||||
"description": "Si está habilitado, se mostrará un conjunto de requisitos de contraseña en la página de creación de la cuenta, como la longitud mínima, caracteres en mayúsculas/minúsculas, etc.",
|
||||
"length": "Largo",
|
||||
"uppercase": "Letras mayúsculas",
|
||||
"lowercase": "Caracteres en minúscula",
|
||||
"numbers": "Números",
|
||||
"special": "Caracteres especiales (%, *, etc.)"
|
||||
},
|
||||
"helpMessages": {
|
||||
"title": "Mensajes de ayuda",
|
||||
"description": "Estos mensajes se mostrarán en la página de creación de la cuenta y en algunos correos electrónicos.",
|
||||
"contactMessage": "Mensaje de contacto",
|
||||
"contactMessageNotice": "Aparece en la parte inferior de todas las páginas excepto admin.",
|
||||
"helpMessage": "Mensaje de ayuda",
|
||||
"helpMessageNotice": "Aparece en la página de creación de cuenta.",
|
||||
"successMessage": "Mensaje de éxito",
|
||||
"successMessageNotice": "Se muestra cuando un usuario crea su cuenta.",
|
||||
"emailMessage": "Mensaje de correo electrónico",
|
||||
"emailMessageNotice": "Aparece en la parte inferior de los correos electrónicos."
|
||||
}
|
||||
}
|
||||
127
lang/setup/fr-fr.json
Normal file
@@ -0,0 +1,127 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Français (FR)"
|
||||
},
|
||||
"strings": {
|
||||
"pageTitle": "Installation - jfa-go",
|
||||
"next": "Suivant",
|
||||
"back": "Retour",
|
||||
"optional": "Optionnel",
|
||||
"serverType": "Type de serveur",
|
||||
"disabled": "Désactivé",
|
||||
"enabled": "Activé",
|
||||
"port": "Port",
|
||||
"message": "Message",
|
||||
"serverAddress": "Adresse du serveur",
|
||||
"emailSubject": "Objet de l'e-mail",
|
||||
"URL": "URL",
|
||||
"apiKey": "Clé API"
|
||||
},
|
||||
"startPage": {
|
||||
"welcome": "Bienvenue !",
|
||||
"pressStart": "Vous devez effectuer quelques opérations pour installer jfa-go. Appuyez sur commencer pour continuer.",
|
||||
"httpsNotice": "Assurez-vous que vous soyez connecté en HTTPS à cette page ou via réseau privé.",
|
||||
"start": "Commencer"
|
||||
},
|
||||
"endPage": {
|
||||
"finished": "Terminé !",
|
||||
"restartMessage": "Il y a d'autres paramètres que vous pouvez configurer sur la page administrateur. Cliquez en dessous pour redémarrer, rafraichissez ensuite la page.",
|
||||
"refreshPage": "Rafraichir"
|
||||
},
|
||||
"language": {
|
||||
"title": "Langue",
|
||||
"description": "Des traductions communautaires sont disponibles pour la plupart des parties de jfa-go. Vous pouvez choisir les langues par défaut ci-dessous, mais les utilisateurs peuvent toujours les modifier s'ils le souhaitent. Si vous souhaitez aider à traduire, inscrivez-vous sur {n} pour commencer à contribuer !",
|
||||
"defaultAdminLang": "Langue administrateur par défaut",
|
||||
"defaultFormLang": "Langue par défaut lors d'une création de compte",
|
||||
"defaultEmailLang": "Langue par défaut des e-mails"
|
||||
},
|
||||
"general": {
|
||||
"title": "Général",
|
||||
"listenAddress": "Adresse d'écoute",
|
||||
"urlBase": "Base URL",
|
||||
"urlBaseNotice": "Nécessaire seulement si vous utilisez un reverse proxy sur un sous-domaine (ex : 'jellyf.in/accounts').",
|
||||
"lightTheme": "Clair",
|
||||
"darkTheme": "Sombre",
|
||||
"useHTTPS": "Utiliser HTTPS",
|
||||
"httpsPort": "Port HTTPS",
|
||||
"useHTTPSNotice": "Recommandé seulement si vous n'utilisez pas de reverse proxy.",
|
||||
"pathToCertificate": "Chemin du certificat",
|
||||
"pathToKeyFile": "Chemin du fichier clé"
|
||||
},
|
||||
"login": {
|
||||
"title": "S'identifier",
|
||||
"description": "Pour accéder à la page d'administrateur, vous devez vous connecter avec la méthode ci-dessous :",
|
||||
"authorizeWithJellyfin": "Autoriser avec Jellyfin/Emby : Les Informations de connexion sont partagées avec Jellyfin, ce qui permet plusieurs utilisateurs.",
|
||||
"authorizeManual": "Utilisateur et Mot de passe : Renseignez manuellement le nom d'utilisateur et le mot de passe.",
|
||||
"adminOnly": "Administrateurs seulement (recommandé)",
|
||||
"emailNotice": "Votre adresse e-mail peut être utilisée pour recevoir des notifications."
|
||||
},
|
||||
"jellyfinEmby": {
|
||||
"title": "Jellyfin/Emby",
|
||||
"description": "Un compte administrateur est requis car l'API ne permet pas la création d'utilisateur. Vous devez créer un compte séparément et cocher 'Autoriser cet utilisateur à gérer le serveur'. Vous pouvez désactiver tout le reste. Une fois créé, renseignez les informations d'identification ici.",
|
||||
"embyNotice": "Le support de Emby est limité et ne permet pas la réinitialisation de mot de passe.",
|
||||
"internal": "Interne",
|
||||
"external": "Externe",
|
||||
"replaceJellyfin": "Nom du serveur",
|
||||
"replaceJellyfinNotice": "Si renseigné, remplacera toutes les occurrences de 'Jellyfin' dans l'application.",
|
||||
"addressExternalNotice": "Laissez vide pour utiliser la même adresse.",
|
||||
"testConnection": "Test de connexion"
|
||||
},
|
||||
"ombi": {
|
||||
"title": "Ombi",
|
||||
"description": "En connectant Ombi, un compte Jellyfin et un compte Ombi seront créés lorsque l'utilisateur rejoindra via jfa-go. Après la fin de l'installation, allez dans les Paramètres pour définir un profil par défaut pour les nouveaux utilisateurs d'Ombi.",
|
||||
"apiKeyNotice": "Trouvez ceci dans le premier onglet des paramètres de Ombi."
|
||||
},
|
||||
"email": {
|
||||
"title": "E-mail",
|
||||
"description": "jfa-go peut envoyer un code PIN de réinitialisation du mot de passe et plusieurs notifications par e-mail. Vous pouvez vous connecter à un serveur SMTP, ou utiliser l'API de {n}.",
|
||||
"method": "Méthode d'envoi",
|
||||
"useEmailAsUsername": "Utilisez l'adresse e-mail comme nom d'utilisateur",
|
||||
"useEmailAsUsernameNotice": "Si activé, les nouveaux utilisateurs se connecteront à Jellyfin/Emby avec cette adresse e-mail au lieu du nom d'utilisateur.",
|
||||
"fromAddress": "Depuis l'adresse",
|
||||
"senderName": "Nom de l'envoyeur",
|
||||
"dateFormat": "Format de la date",
|
||||
"dateFormatNotice": "La date suis le format srtftime. Pour plus d'informations, consultez {n}.",
|
||||
"encryption": "Chiffrement",
|
||||
"mailgunApiURL": "URL de l'API"
|
||||
},
|
||||
"notifications": {
|
||||
"title": "Notifications",
|
||||
"description": "Si activé, vous pouvez choisir (par invitation) de recevoir un e-mail lorsque l'invitation expire, ou lorsque l'utilisateur est créé. Si vous ne choisissez pas la méthode de connexion par Jellyfin, assurez-vous d'avoir fourni votre adresse e-mail."
|
||||
},
|
||||
"welcomeEmails": {
|
||||
"title": "E-mails de bienvenue",
|
||||
"description": "Si activé, un e-mail sera envoyé aux nouveaux utilisateurs avec l'URL de Jellyfin/Emby et leur nom d'utilisateur."
|
||||
},
|
||||
"inviteEmails": {
|
||||
"title": "E-mails d'invitation",
|
||||
"description": "Si activé, vous pouvez envoyer une invitation directement à l'adresse e-mail de l'utilisateur. Parce que vous pourriez utiliser un reverse proxy, vous devez renseigner l'URL d'accès aux invitations. Renseignez votre Base URL et ajoutez '/invite'."
|
||||
},
|
||||
"passwordResets": {
|
||||
"title": "Réinitialisation de mot de passe",
|
||||
"description": "Lorsqu'un utilisateur essaie de réinitialiser son mot de passe, Jellyfin créé un fichier nommé 'passwordreset-*.json' qui contient le code PIN. jfa-go lit le fichier et envoie le code PIN à l'utilisateur.",
|
||||
"pathToJellyfin": "Chemin du dossier de configuration de Jellyfin",
|
||||
"pathToJellyfinNotice": "Si vous ne savez pas où c'est, essayez de réinitialiser votre mot de passe dans Jellyfin. Une popup avec '<path to jellyfin>/passwordreset-*.json' apparaitra."
|
||||
},
|
||||
"passwordValidation": {
|
||||
"title": "Validation du mot de passe",
|
||||
"description": "Si cette option est activée, un ensemble d'exigences de mot de passe s'affichera sur la page de création de compte, comme la longueur minimale, les majuscules/minuscules, etc.",
|
||||
"length": "Longueur",
|
||||
"uppercase": "Majuscules",
|
||||
"lowercase": "Minuscules",
|
||||
"numbers": "Nombres",
|
||||
"special": "Caractères spéciaux (%, *, etc.)"
|
||||
},
|
||||
"helpMessages": {
|
||||
"title": "Messages d'aide",
|
||||
"description": "Ces messages s'afficheront dans la page de création de compte et dans certains e-mails.",
|
||||
"contactMessage": "Message de contact",
|
||||
"contactMessageNotice": "S'affiche au bas de toutes les pages sauf administrateur.",
|
||||
"helpMessage": "Message d'aide",
|
||||
"helpMessageNotice": "S'affiche sur la page de création de compte.",
|
||||
"successMessage": "Message de réussite",
|
||||
"successMessageNotice": "S'affiche lorsqu'un utilisateur crée son compte.",
|
||||
"emailMessage": "Message de l'e-mail",
|
||||
"emailMessageNotice": "S'affiche au bas des e-mails."
|
||||
}
|
||||
}
|
||||
127
lang/setup/id-id.json
Normal file
@@ -0,0 +1,127 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Bahasa Indonesia (ID)"
|
||||
},
|
||||
"strings": {
|
||||
"pageTitle": "Persiapan - jfa-go",
|
||||
"next": "Lanjut",
|
||||
"back": "Kembali",
|
||||
"optional": "Pilihan",
|
||||
"serverType": "Tipe Server",
|
||||
"disabled": "Dinonaktifkan",
|
||||
"enabled": "Diaktifkan",
|
||||
"port": "Port",
|
||||
"message": "Pesan",
|
||||
"serverAddress": "Alamat Server",
|
||||
"emailSubject": "Subjek Email",
|
||||
"URL": "URL",
|
||||
"apiKey": "Kunci API"
|
||||
},
|
||||
"startPage": {
|
||||
"welcome": "Selamat Datang!",
|
||||
"pressStart": "Anda perlu melakukan beberapa hal untuk menyiapkan jfa-go. Tekan mulai untuk melanjutkan.",
|
||||
"httpsNotice": "Pastikan Anda mengakses halaman ini melalui HTTPS atau di jaringan pribadi.",
|
||||
"start": "Mulai"
|
||||
},
|
||||
"endPage": {
|
||||
"finished": "Selesai!",
|
||||
"restartMessage": "Ada lebih banyak pengaturan yang dapat Anda konfigurasi di halaman admin. Klik di bawah untuk restart, lalu segarkan halaman.",
|
||||
"refreshPage": "Segarkan"
|
||||
},
|
||||
"language": {
|
||||
"title": "Bahasa",
|
||||
"description": "Terjemahan komunitas tersedia untuk sebagian besar bagian dari jfa-go. Anda dapat memilih bahasa default di bawah ini, tetapi pengguna masih dapat mengubahnya jika mereka mau. Jika Anda ingin membantu menerjemahkan, daftar ke {n} untuk mulai berkontribusi!",
|
||||
"defaultAdminLang": "Bahasa admin default",
|
||||
"defaultFormLang": "Bahasa default pembuatan akun",
|
||||
"defaultEmailLang": "Bahasa default email"
|
||||
},
|
||||
"general": {
|
||||
"title": "Umum",
|
||||
"listenAddress": "Listen Address",
|
||||
"urlBase": "Basis URL",
|
||||
"urlBaseNotice": "Hanya diperlukan jika menggunakan reverse proxy pada subdomain (misalnya 'jellyf.in/accounts').",
|
||||
"lightTheme": "Terang",
|
||||
"darkTheme": "Gelap",
|
||||
"useHTTPS": "Gunakan HTTPS",
|
||||
"httpsPort": "Port HTTPS",
|
||||
"useHTTPSNotice": "Hanya disarankan jika Anda tidak menggunakan reverse proxy.",
|
||||
"pathToCertificate": "Jalur ke sertifikat",
|
||||
"pathToKeyFile": "Jalur ke file kunci"
|
||||
},
|
||||
"login": {
|
||||
"title": "Masuk",
|
||||
"description": "Untuk mengakses halaman admin, Anda perlu masuk dengan metode di bawah ini:",
|
||||
"authorizeWithJellyfin": "Otorisasi dengan Jellyfin / Emby: Detail login dibagikan dengan Jellyfin, yang memungkinkan banyak pengguna.",
|
||||
"authorizeManual": "Username dan Password: Atur username dan password secara manual.",
|
||||
"adminOnly": "Hanya pengguna admin (disarankan)",
|
||||
"emailNotice": "Alamat email Anda dapat digunakan untuk menerima pemberitahuan."
|
||||
},
|
||||
"jellyfinEmby": {
|
||||
"title": "Jellyfin/Emby",
|
||||
"description": "Akun admin diperlukan karena API tidak mengizinkan pembuatan pengguna menggunakan kunci API. Anda harus membuat akun terpisah dan mencentang 'Izinkan pengguna ini untuk mengelola server'. Anda dapat menonaktifkan yang lainnya. Setelah selesai, masukkan detail login di sini.",
|
||||
"embyNotice": "Dukungan Emby terbatas dan tidak mendukung penyetelan ulang kata sandi.",
|
||||
"internal": "Internal",
|
||||
"external": "Eksternal",
|
||||
"replaceJellyfin": "Nama Server",
|
||||
"replaceJellyfinNotice": "Jika diberikan, ini akan menggantikan kemunculan kata 'Jellyfin' di aplikasi.",
|
||||
"addressExternalNotice": "Biarkan kosong untuk menggunakan alamat yang sama.",
|
||||
"testConnection": "Tes Koneksi"
|
||||
},
|
||||
"ombi": {
|
||||
"title": "Ombi",
|
||||
"description": "Dengan terhubung ke Ombi, akun Jellyfin dan Ombi akan dibuat saat pengguna bergabung melalui jfa-go. Setelah pengaturan selesai, buka Pengaturan untuk mengatur profil default untuk pengguna ombi baru.",
|
||||
"apiKeyNotice": "Temukan ini di tab pertama pengaturan Ombi."
|
||||
},
|
||||
"email": {
|
||||
"title": "Email",
|
||||
"description": "jfa-go dapat mengirimkan PIN pengaturan ulang kata sandi dan berbagai notifikasi melalui email. Anda bisa terhubung ke server SMTP, atau menggunakan {n} API.",
|
||||
"method": "Metode pengiriman",
|
||||
"useEmailAsUsername": "Gunakan alamat email sebagai nama pengguna",
|
||||
"useEmailAsUsernameNotice": "Jika diaktifkan, pengguna baru akan masuk ke Jellyfin / Emby dengan alamat email mereka, bukan nama pengguna.",
|
||||
"fromAddress": "Dari Alamat",
|
||||
"senderName": "Nama Pengirim",
|
||||
"dateFormat": "Format Tanggal",
|
||||
"dateFormatNotice": "Tanggal mengikuti format strftime. Untuk info lebih lanjut, kunjungi {n}.",
|
||||
"encryption": "Enkripsi",
|
||||
"mailgunApiURL": "URL API"
|
||||
},
|
||||
"notifications": {
|
||||
"title": "Pemberitahuan",
|
||||
"description": "Jika diaktifkan, Anda dapat memilih (per undangan) untuk menerima email saat undangan kedaluwarsa, atau pengguna dibuat. Jika Anda tidak memilih metode login Jellyfin, pastikan Anda memberikan alamat email Anda."
|
||||
},
|
||||
"welcomeEmails": {
|
||||
"title": "Email selamat datang",
|
||||
"description": "Jika diaktifkan, email akan dikirim ke pengguna baru dengan URL Jellyfin / Emby dan nama pengguna mereka."
|
||||
},
|
||||
"inviteEmails": {
|
||||
"title": "Email Undangan",
|
||||
"description": "Jika diaktifkan, Anda dapat mengirim undangan langsung ke alamat email pengguna. Karena Anda mungkin menggunakan reverse proxy, Anda perlu memberikan dari mana URL undangan diakses. Tulis Basis URL Anda, dan tambahkan '/ invite'."
|
||||
},
|
||||
"passwordResets": {
|
||||
"title": "Reset Kata Sandi",
|
||||
"description": "Ketika pengguna mencoba mengatur ulang kata sandinya, Jellyfin membuat file bernama 'passwordreset - *. Json' yang berisi PIN. jfa-go membaca file dan mengirimkan PIN ke pengguna.",
|
||||
"pathToJellyfin": "Jalur ke direktori konfigurasi Jellyfin",
|
||||
"pathToJellyfinNotice": "Jika Anda tidak tahu di mana ini, coba setel ulang kata sandi Anda di Jellyfin. Sebuah popup dengan '<path to jellyfin> / passwordreset - *. Json' akan muncul."
|
||||
},
|
||||
"passwordValidation": {
|
||||
"title": "Validasi Kata Sandi",
|
||||
"description": "Jika diaktifkan, sekumpulan persyaratan kata sandi akan ditampilkan di halaman pembuatan akun, seperti panjang minimum, karakter huruf besar / kecil, dll.",
|
||||
"length": "Panjang",
|
||||
"uppercase": "Karakter huruf besar",
|
||||
"lowercase": "Karakter huruf kecil",
|
||||
"numbers": "Angka",
|
||||
"special": "Karakter khusus (%, *, dll.)"
|
||||
},
|
||||
"helpMessages": {
|
||||
"title": "Pesan Bantuan",
|
||||
"description": "Pesan ini akan ditampilkan di halaman pembuatan akun dan di beberapa email.",
|
||||
"contactMessage": "Pesan Kontak",
|
||||
"contactMessageNotice": "Ditampilkan di bagian bawah semua halaman kecuali admin.",
|
||||
"helpMessage": "Pesan Bantuan",
|
||||
"helpMessageNotice": "Ditampilkan di halaman pembuatan akun.",
|
||||
"successMessage": "Pesan Sukses",
|
||||
"successMessageNotice": "Ditampilkan saat pengguna membuat akunnya.",
|
||||
"emailMessage": "Pesan Email",
|
||||
"emailMessageNotice": "Ditampilkan di bagian bawah email."
|
||||
}
|
||||
}
|
||||
134
lang/setup/nl-nl.json
Normal file
@@ -0,0 +1,134 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Nederlands (NL)"
|
||||
},
|
||||
"strings": {
|
||||
"pageTitle": "Insstallatie - jfa-go",
|
||||
"next": "Volgende",
|
||||
"back": "Terug",
|
||||
"optional": "Optioneel",
|
||||
"serverType": "Servertype",
|
||||
"disabled": "Uitgeschakeld",
|
||||
"enabled": "Ingeschakeld",
|
||||
"port": "Poort",
|
||||
"message": "Bericht",
|
||||
"serverAddress": "Serveradres",
|
||||
"emailSubject": "Onderwerp e-mail",
|
||||
"URL": "URL",
|
||||
"apiKey": "API-sleutel"
|
||||
},
|
||||
"startPage": {
|
||||
"welcome": "Welkom!",
|
||||
"pressStart": "Je moet een paar dingen doen om jfa-go te installeren. Druk op start om verder te gaan.",
|
||||
"httpsNotice": "Zorg ervoor dat je deze pagina bezoekt via HTTPS of een privénetwerk.",
|
||||
"start": "Start"
|
||||
},
|
||||
"endPage": {
|
||||
"finished": "Klaar!",
|
||||
"restartMessage": "Er staan meer instellingen op de beheerderspagina. Druk op de knop hieronder om opnieuw op te starten, en ververs daarna de pagina.",
|
||||
"refreshPage": "Verversen"
|
||||
},
|
||||
"language": {
|
||||
"title": "Taal",
|
||||
"description": "Er zijn gemeenschapsvertalingen beschikbaar voor de meeste onderdelen van jfa-go. Je kunt hieronder de standaardtaal instellen, maar gebruikers kunnen die aanpassen indien gewenst. Als je wilt helpen met vertalen, meld je dan aan bij {n} en begin met vertalen!",
|
||||
"defaultAdminLang": "Standaardtaal (beheer)",
|
||||
"defaultFormLang": "Standaardtaal aanmaken nieuwe account",
|
||||
"defaultEmailLang": "Standaardtaal (e-mails)"
|
||||
},
|
||||
"general": {
|
||||
"title": "Algemeen",
|
||||
"listenAddress": "Adres",
|
||||
"urlBase": "URL-basis",
|
||||
"urlBaseNotice": "Alleen nodig bij gebruik van reverse proxy op een subdomein (bijv. 'jellyf.in/accounts').",
|
||||
"lightTheme": "Licht",
|
||||
"darkTheme": "Donker",
|
||||
"useHTTPS": "Gebruik HTTPS",
|
||||
"httpsPort": "HTTPS poort",
|
||||
"useHTTPSNotice": "Alleen aanbevolen als je geen reverse proxy gebruikt.",
|
||||
"pathToCertificate": "Pad naar certificaat",
|
||||
"pathToKeyFile": "Pad naar sleutelbestand"
|
||||
},
|
||||
"login": {
|
||||
"title": "Inloggen",
|
||||
"description": "Om de beheerderspagina te openen moet je inloggen met één van onderstaande methodes:",
|
||||
"authorizeWithJellyfin": "Jellyfin/Emby authorisatie: Inloggegevens worden gedeeld met Jellyfin, meerdere gebruikers mogelijk.",
|
||||
"authorizeManual": "Gebruikersnaam en wachtwoord: Stel handmatig een gebruikersnaam en wachtwoord in.",
|
||||
"adminOnly": "Alleen beheerders (aanbevolen)",
|
||||
"emailNotice": "Je e-mailadres kan gebruikt worden om meldingen te ontvangen."
|
||||
},
|
||||
"jellyfinEmby": {
|
||||
"title": "Jellyfin/Emby",
|
||||
"description": "Er is een beheerdersaccount nodig, omdat via de API geen gebruikers aangemaakt kunnen worden. Maak een aparte account aan en vink 'Deze gebruiker kan de server beheren' aan. Alle andere rechten kunnen uitgeschakeld worden. Vul daarna hier de inloggegevens in.",
|
||||
"embyNotice": "Ondersteuning voor Emby is beperkt en ondersteunt geen wachtwoordresets.",
|
||||
"internal": "Intern",
|
||||
"external": "Extern",
|
||||
"replaceJellyfin": "Servernaam",
|
||||
"replaceJellyfinNotice": "Indien ingevuld wordt overal in de app het woord 'Jellyfin' hierdoor vervangen.",
|
||||
"addressExternalNotice": "Laat leeg om hetzelfde adres te gebruiken.",
|
||||
"testConnection": "Test verbinding"
|
||||
},
|
||||
"ombi": {
|
||||
"title": "Ombi",
|
||||
"description": "Bij verbinding met Ombi, worden voor nieuwe gebruikers via jfa-go zowel een Jellyfin als een Ombi account aangemaakt. Ga nadat de setup voltooid is naar instellingen om een standaardprofiel voor nieuwe Ombi-gebruikers te kiezen.",
|
||||
"apiKeyNotice": "Te vinden op het eerste tabblad van de Ombi-instellingen."
|
||||
},
|
||||
"email": {
|
||||
"title": "E-mail",
|
||||
"description": "jfa-go kan wachtwoord reset PINs en meldingen via e-mail versturen. Je kunt verbinding maken met een SMTP server, of de {n} API gebruiken.",
|
||||
"method": "Verstuurmethode",
|
||||
"useEmailAsUsername": "Gebruik e-mailadres als gebruikersnaam",
|
||||
"useEmailAsUsernameNotice": "Indien ingeschakeld wordt voor nieuwe Jellyfin/Emby-gebruikers hun e-mailadres in plaats van gebruikersnaam gebruikt.",
|
||||
"fromAddress": "Afzenderadres",
|
||||
"senderName": "Naam afzender",
|
||||
"dateFormat": "Datumformaat",
|
||||
"dateFormatNotice": "Datum volgend het strftime formaat. Meer info op {n}.",
|
||||
"encryption": "Versleuteling",
|
||||
"mailgunApiURL": "API-URL"
|
||||
},
|
||||
"notifications": {
|
||||
"title": "Meldingen",
|
||||
"description": "Indien ingeschakeld kun je er (per uitnodiging) voor kiezen om een e-mail te ontvangen wanneer een uitnodiging verloopt of er een gebruiker wordt aangemaakt. Als je niet inlogt via Jellyfin, controleer dan dat je je e-mailadres hebt ingevuld."
|
||||
},
|
||||
"welcomeEmails": {
|
||||
"title": "Welkomste-mails",
|
||||
"description": "Indien ingeschakeld wordt er een e-mail gestuurd aan nieuwe gebruikers met de Jellyfin/Emby-URL en hun gebruikersnaam."
|
||||
},
|
||||
"inviteEmails": {
|
||||
"title": "Uitnodigingse-mails",
|
||||
"description": "Indien ingeschakeld kun je uitnodigingen direct naar het e-mailadres van gebruikers sturen. Omdat je misschien een reverse proxy gebruikt moet je het URL opgeven waarlangs uitnodigingen geopend worden. Geef de URL-basis op, gevolgd door '/invite'."
|
||||
},
|
||||
"passwordResets": {
|
||||
"title": "Wachtwoordresets",
|
||||
"description": "Wanneer een gebruiker een wachtwoordreset aanvraagt, maakt Jellyfin een bestand aan dat 'passwordreset-*.json' heet en een PIN bevat. jfa-go leest dit bestand uit en stuurt de PIN naar de gebruiker.",
|
||||
"pathToJellyfin": "Pad naar Jellyfin configuratiemap",
|
||||
"pathToJellyfinNotice": "Als je niet weet waar dit is, probeer de je wachtwoord te resetten in Jellyfin. Er verschijnt dan een popup met '<path to jellyfin>/passwordreset-*.json'."
|
||||
},
|
||||
"passwordValidation": {
|
||||
"title": "Wachtwoordvalidatie",
|
||||
"description": "Indien ingeschakeld worden er op de account-aanmaakpagina een aantal wachtwoordvereisten getoond, zoals minimumlengte, hoofd-/kleine letters, enz.",
|
||||
"length": "Lengte",
|
||||
"uppercase": "Hoofdletters",
|
||||
"lowercase": "Kleine letters",
|
||||
"numbers": "Cijfers",
|
||||
"special": "Bijzondere tekens (%, *, etc.)"
|
||||
},
|
||||
"helpMessages": {
|
||||
"title": "Uitleg",
|
||||
"description": "Deze teksten worden getoond bij de account-aanmaakpagina en in sommige e-mails.",
|
||||
"contactMessage": "Contacttekst",
|
||||
"contactMessageNotice": "Getoond onderaan elke pagina behalve beheer.",
|
||||
"helpMessage": "Helpbericht",
|
||||
"helpMessageNotice": "Getoond op de account-aanmaakpagina.",
|
||||
"successMessage": "Succesbericht",
|
||||
"successMessageNotice": "Getoond wanneer een gebruiker een account aanmaakt.",
|
||||
"emailMessage": "E-mailtext",
|
||||
"emailMessageNotice": "Getoond onderaan e-mails."
|
||||
},
|
||||
"updates": {
|
||||
"unstable": "Instabiel",
|
||||
"updateChannel": "Update kanaal",
|
||||
"stable": "Stabiel",
|
||||
"title": "Updates",
|
||||
"description": "Vink aan om een melding te krijgen wanneer nieuwe updates beschikbaar zijn. jfa-go controleert {n} elke 30 minuten. Er worden geen IPs of persoonsgegevens verzameld."
|
||||
}
|
||||
}
|
||||
134
lang/setup/pt-br.json
Normal file
@@ -0,0 +1,134 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Português (BR)"
|
||||
},
|
||||
"strings": {
|
||||
"pageTitle": "Configuração - jfa-go",
|
||||
"next": "Próximo",
|
||||
"back": "Voltar",
|
||||
"optional": "Opcional",
|
||||
"serverType": "Tipo de Servidor",
|
||||
"disabled": "Desativado",
|
||||
"enabled": "Habilitado",
|
||||
"port": "Porta",
|
||||
"message": "Mensagem",
|
||||
"serverAddress": "Endereço do Servidor",
|
||||
"emailSubject": "Assunto do Email",
|
||||
"URL": "URL",
|
||||
"apiKey": "Chave API"
|
||||
},
|
||||
"startPage": {
|
||||
"welcome": "Bem Vindo!",
|
||||
"pressStart": "Você precisará fazer algumas coisas para configurar o jfa-go. Clique em iniciar para progredir.",
|
||||
"httpsNotice": "Certifique-se de que está acessando esta página via HTTPS ou em uma rede privada.",
|
||||
"start": "Iniciar"
|
||||
},
|
||||
"endPage": {
|
||||
"finished": "Finalizado!",
|
||||
"restartMessage": "Existem mais opções que você pode definir na página do administrador. Clique abaixo para reiniciar e atualize a página.",
|
||||
"refreshPage": "Atualizar"
|
||||
},
|
||||
"language": {
|
||||
"title": "Idioma",
|
||||
"description": "As traduções da comunidade estão disponíveis para a maior parte do jfa-go. Você pode escolher os idiomas padrão abaixo, mas os usuários ainda podem alterá-los caso desejem. Se você quiser ajudar na tradução, inscreva-se no {n} para contribuir!",
|
||||
"defaultAdminLang": "Idioma padrão do administrador",
|
||||
"defaultFormLang": "Idioma padrão para criação de conta",
|
||||
"defaultEmailLang": "Idioma padrão para o email"
|
||||
},
|
||||
"general": {
|
||||
"title": "Geral",
|
||||
"listenAddress": "Endereço de Escuta",
|
||||
"urlBase": "URL Base",
|
||||
"urlBaseNotice": "Necessário apenas se estiver usando um proxy reverso em um subdomínio (por exemplo, 'jellyf.in/accounts').",
|
||||
"lightTheme": "Claro",
|
||||
"darkTheme": "Escuro",
|
||||
"useHTTPS": "Usar HTTPS",
|
||||
"httpsPort": "Porta HTTPS",
|
||||
"useHTTPSNotice": "Recomendado apenas se você não estiver usando um proxy reverso.",
|
||||
"pathToCertificate": "Local do certificado",
|
||||
"pathToKeyFile": "Local da chave do arquivo"
|
||||
},
|
||||
"login": {
|
||||
"title": "Login",
|
||||
"description": "Para acessar a página do administrador, você precisa fazer o login com o método abaixo:",
|
||||
"authorizeWithJellyfin": "Autorizar com Jellyfin/Emby: Os detalhes de login são compartilhados com Jellyfin, o que permite vários usuários.",
|
||||
"authorizeManual": "Nome de usuário e senha: Defina manualmente o nome de usuário e a senha.",
|
||||
"adminOnly": "Apenas usuários administradores (recomendado)",
|
||||
"emailNotice": "Seu endereço de email pode ser usado para receber notificações."
|
||||
},
|
||||
"jellyfinEmby": {
|
||||
"title": "Jellyfin/Emby",
|
||||
"description": "Uma conta de administrador é necessária porque a API não permite a criação de usuários usando uma chave de API. Você deve criar uma outra conta marcando a opção 'Permitir este usuário administrar o servidor'. Você pode desativar todas outras opções. Uma vez feito isso, insira os detalhes de login aqui.",
|
||||
"embyNotice": "O suporte ao Emby é limitado e não tem suporte em redefinir senha.",
|
||||
"internal": "Interno",
|
||||
"external": "Externo",
|
||||
"replaceJellyfin": "Nome do servidor",
|
||||
"replaceJellyfinNotice": "Se fornecido, ele substituirá qualquer ocorrência de 'Jellyfin' no aplicativo.",
|
||||
"addressExternalNotice": "Deixe em branco para usar o mesmo endereço.",
|
||||
"testConnection": "Teste de Conexão"
|
||||
},
|
||||
"ombi": {
|
||||
"title": "Ombi",
|
||||
"description": "Ao se conectar ao Ombi, as contas no Jellyfin e Ombi serão criadas quando um usuário se cadastrar através do jfa-go. Depois de concluída a configuração, vá para Configurações para definir um perfil padrão para novos usuários de ombi.",
|
||||
"apiKeyNotice": "Encontre isso na primeira guia nas configurações do Ombi."
|
||||
},
|
||||
"email": {
|
||||
"title": "Email",
|
||||
"description": "jfa-go pode enviar PINs de redefinição de senha e várias notificações por email. Você pode se conectar a um servidor SMTP ou usar a {n} API.",
|
||||
"method": "Método de envio",
|
||||
"useEmailAsUsername": "Usar endereços de email como nome de usuário",
|
||||
"useEmailAsUsernameNotice": "Se habilitado, novos usuários farão login no Jellyfin/Emby com seu endereço de email em vez de um nome de usuário.",
|
||||
"fromAddress": "A partir do endereço",
|
||||
"senderName": "Nome do remetente",
|
||||
"dateFormat": "Formato da Data",
|
||||
"dateFormatNotice": "A data segue o formato strftime. Para obter mais informações, visite {n}.",
|
||||
"encryption": "Encriptação",
|
||||
"mailgunApiURL": "API URL"
|
||||
},
|
||||
"notifications": {
|
||||
"title": "Notificações",
|
||||
"description": "Se ativado, você pode escolher (por convite) receber um email quando um convite expirar ou um usuário for criado. Se você não escolheu o método de login Jellyfin, certifique-se de fornecer seu endereço de e-mail."
|
||||
},
|
||||
"welcomeEmails": {
|
||||
"title": "Email de boas-vindas",
|
||||
"description": "Se habilitado, um email será enviado para os novos usuários Jellyfin/Emby."
|
||||
},
|
||||
"inviteEmails": {
|
||||
"title": "Convidar por Emails",
|
||||
"description": "Se ativado, você pode enviar convites diretamente para o endereço de email do usuário. Como você pode estar usando um proxy reverso, é necessário fornecer a URL de onde os convites são acessados. Escreva a sua URL Base e acrescente '/invite'."
|
||||
},
|
||||
"passwordResets": {
|
||||
"title": "Redefinir Senha",
|
||||
"description": "Quando um usuário tenta redefinir sua senha, o Jellyfin cria um arquivo chamado 'passwordreset-*.json' que contém um PIN. jfa-go lê o arquivo e envia o PIN ao usuário.",
|
||||
"pathToJellyfin": "Local do diretório de configuração do Jellyfin",
|
||||
"pathToJellyfinNotice": "Se você não sabe o local onde fica, tente redefinir sua senha no Jellyfin. Um pop-up com '<path to jellyfin>/passwordreset-*.json' aparecerá."
|
||||
},
|
||||
"passwordValidation": {
|
||||
"title": "Validar Senha",
|
||||
"description": "Se ativado, o requisitos de senha será mostrado na página de criação da conta, como tamanho mínimo, caracteres maiúsculos/minúsculos, etc.",
|
||||
"length": "Tamanho",
|
||||
"uppercase": "Caracteres maiúsculos",
|
||||
"lowercase": "Caracteres minúsculos",
|
||||
"numbers": "Números",
|
||||
"special": "Caracteres Especial (%, *, etc.)"
|
||||
},
|
||||
"helpMessages": {
|
||||
"title": "Mensagem de Ajuda",
|
||||
"description": "Essas mensagens serão exibidas na página de criação de conta e em alguns emails.",
|
||||
"contactMessage": "Mensagem de Contato",
|
||||
"contactMessageNotice": "Exibido na parte inferior de todas as páginas, exceto na administradora.",
|
||||
"helpMessage": "Mensagem de Ajuda",
|
||||
"helpMessageNotice": "Exibido na página de criação de conta.",
|
||||
"successMessage": "Mensagem de Sucesso",
|
||||
"successMessageNotice": "Exibido quando um usuário cria sua conta.",
|
||||
"emailMessage": "Mensagem de Email",
|
||||
"emailMessageNotice": "Exibido na parte inferior dos emails."
|
||||
},
|
||||
"updates": {
|
||||
"title": "Atualizações",
|
||||
"description": "Ative para ser notificado quando novas atualizações estiverem disponíveis. jfa-go verificará {n} a cada 30 minutos. Nenhum IP ou informação de identificação pessoal é coletada.",
|
||||
"updateChannel": "Canal de Atualização",
|
||||
"stable": "Estável",
|
||||
"unstable": "Instável"
|
||||
}
|
||||
}
|
||||
127
lang/setup/sv-se.json
Normal file
@@ -0,0 +1,127 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Svenska (SV)"
|
||||
},
|
||||
"strings": {
|
||||
"pageTitle": "Konfigurera - jfa-go",
|
||||
"next": "Nästa",
|
||||
"back": "Tillbaka",
|
||||
"optional": "Valfri",
|
||||
"serverType": "Servertyp",
|
||||
"disabled": "Inaktiverad",
|
||||
"enabled": "Aktiverad",
|
||||
"port": "Port",
|
||||
"message": "Meddelande",
|
||||
"serverAddress": "Serveradress",
|
||||
"emailSubject": "E-postämne",
|
||||
"URL": "URL",
|
||||
"apiKey": "API-nyckel"
|
||||
},
|
||||
"startPage": {
|
||||
"welcome": "Välkommen!",
|
||||
"pressStart": "Du måste göra några saker för att konfigurera jfa-go. Tryck på starta för att fortsätta.",
|
||||
"httpsNotice": "Se till att du kommer åt den här sidan via HTTPS eller via ett privat nätverk.",
|
||||
"start": "Starta"
|
||||
},
|
||||
"endPage": {
|
||||
"finished": "Färdig!",
|
||||
"restartMessage": "Det finns fler inställningar som du kan konfigurera på administratörssidan. Klicka nedan för att starta om och uppdatera sedan sidan.",
|
||||
"refreshPage": "Uppdatera"
|
||||
},
|
||||
"language": {
|
||||
"title": "Språk",
|
||||
"description": "Gemensamma översättningar är tillgängliga för de flesta delar av jfa-go. Du kan välja standardspråken nedan, men användarna kan ändå ändra det om de vill. Om du vill hjälpa till med översättningen kan du registrera dig på {n} för att börja bidra!",
|
||||
"defaultAdminLang": "Standard admin-språk",
|
||||
"defaultFormLang": "Standardspråk för skapande av konto",
|
||||
"defaultEmailLang": "Standard e-postspråk"
|
||||
},
|
||||
"general": {
|
||||
"title": "Allmänt",
|
||||
"listenAddress": "Lyssnar på adress",
|
||||
"urlBase": "URL-bas",
|
||||
"urlBaseNotice": "Behövs bara om du använder en omvänd proxy på en underdomän (t.ex. 'jellyf.in/accounts').",
|
||||
"lightTheme": "Ljus",
|
||||
"darkTheme": "Mörk",
|
||||
"useHTTPS": "Använd HTTPS",
|
||||
"httpsPort": "HTTPS port",
|
||||
"useHTTPSNotice": "Rekommenderas endast om du inte använder en omvänd proxy.",
|
||||
"pathToCertificate": "Sökväg till certifikat",
|
||||
"pathToKeyFile": "Sökväg till privat nyckel"
|
||||
},
|
||||
"login": {
|
||||
"title": "Logga in",
|
||||
"description": "För att komma åt administratörssidan måste du logga in med en metod nedan:",
|
||||
"authorizeWithJellyfin": "Auktorisera med Jellyfin/Emby: Inloggningsuppgifter delas med Jellyfin, vilket möjliggör flera användare.",
|
||||
"authorizeManual": "Användarnamn och lösenord: Ange användarnamn och lösenord manuellt.",
|
||||
"adminOnly": "Endast administratörsanvändare (rekommenderas)",
|
||||
"emailNotice": "Din e-postadress kan användas för att ta emot aviseringar."
|
||||
},
|
||||
"jellyfinEmby": {
|
||||
"title": "Jellyfin/Emby",
|
||||
"description": "Ett administratörskonto behövs eftersom API: et inte tillåter användarskapande med en API-nyckel. Du bör skapa ett separat konto och markera \"Tillåt den här användaren att hantera servern\". Du kan inaktivera allt annat. När du är klar anger du inloggningsuppgifterna här.",
|
||||
"embyNotice": "Emby-stöd är begränsat och stöder inte återställning av lösenord.",
|
||||
"internal": "Intern",
|
||||
"external": "Extern",
|
||||
"replaceJellyfin": "Servernamn",
|
||||
"replaceJellyfinNotice": "Om detta anges kommer det att ersätta alla förekomster av 'Jellyfin' i appen.",
|
||||
"addressExternalNotice": "Lämna tomt för att använda samma adress.",
|
||||
"testConnection": "Testa anslutning"
|
||||
},
|
||||
"ombi": {
|
||||
"title": "Ombi",
|
||||
"description": "Genom att ansluta till Ombi skapas både ett Jellyfin- och Ombi-konto när en användare går med genom jfa-go. Efter installationen, om du är klar, gå till Inställningar för att ställa in en standardprofil för nya ombi-användare.",
|
||||
"apiKeyNotice": "Hitta detta i den första fliken i Ombi-inställningarna."
|
||||
},
|
||||
"email": {
|
||||
"title": "E-post",
|
||||
"description": "jfa-go kan skicka PIN-koder för återställning av lösenord och olika meddelanden via e-post. Du kan ansluta till en SMTP-server eller använda {n} API.",
|
||||
"method": "Sändningsmetod",
|
||||
"useEmailAsUsername": "Använd e-postadresser som användarnamn",
|
||||
"useEmailAsUsernameNotice": "Om detta är aktiverat kommer nya användare att logga in på Jellyfin / Emby med sin e-postadress istället för ett användarnamn.",
|
||||
"fromAddress": "Från adress",
|
||||
"senderName": "Avsändarens namn",
|
||||
"dateFormat": "Datumformat",
|
||||
"dateFormatNotice": "Datum följer strftime-formatet. Mer information finns på {n}.",
|
||||
"encryption": "Kryptering",
|
||||
"mailgunApiURL": "API URL"
|
||||
},
|
||||
"notifications": {
|
||||
"title": "Aviseringar",
|
||||
"description": "Om detta är aktiverat kan du välja (per inbjudan) att få ett e-postmeddelande när en inbjudan upphör eller när en användare skapas. Om du inte valde inloggningsmetoden Jellyfin, se till att du angav din e-postadress."
|
||||
},
|
||||
"welcomeEmails": {
|
||||
"title": "Välkomstmeddelanden",
|
||||
"description": "Om aktiverat skickas ett e-postmeddelande till nya användare med Jellyfin/Emby URL och deras användarnamn."
|
||||
},
|
||||
"inviteEmails": {
|
||||
"title": "Inbjudnings e-post",
|
||||
"description": "Om detta är aktiverat kan du skicka inbjudningar direkt till en användares e-postadress. Eftersom du kanske använder en omvänd proxy måste du ange att webbadressinbjudningar nås från. Skriv din URL-bas och lägg till '/invite'."
|
||||
},
|
||||
"passwordResets": {
|
||||
"title": "Lösenordsåterställningar",
|
||||
"description": "När en användare försöker återställa sitt lösenord skapar Jellyfin en fil med namnet 'passwordreset-*.json' som innehåller en PIN-kod. jfa-go läser filen och skickar PIN-koden till användaren.",
|
||||
"pathToJellyfin": "Sökväg till Jellyfin-konfigurationskatalogen",
|
||||
"pathToJellyfinNotice": "Om du inte vet var det är, försök återställa lösenordet i Jellyfin. En popup med '<sökväg till jellyfin>/passwordreset-*.json' kommer då visas."
|
||||
},
|
||||
"passwordValidation": {
|
||||
"title": "Validering av lösenord",
|
||||
"description": "Om detta är aktiverat kommer en uppsättning lösenordskrav att visas på sidan för skapande av konto, till exempel minsta längd, stora/små bokstäver etc.",
|
||||
"length": "Längd",
|
||||
"uppercase": "Versaler",
|
||||
"lowercase": "Gemener",
|
||||
"numbers": "Nummer",
|
||||
"special": "Specialtecken (%, *, etc.)"
|
||||
},
|
||||
"helpMessages": {
|
||||
"title": "Hjälpmeddelanden",
|
||||
"description": "Dessa meddelanden visas på sidan för skapande av konto och i vissa e-postmeddelanden.",
|
||||
"contactMessage": "Kontaktmeddelande",
|
||||
"contactMessageNotice": "Visas längst ner på alla sidor utom admin.",
|
||||
"helpMessage": "Hjälpmeddelande",
|
||||
"helpMessageNotice": "Visas på sidan för att skapa konto.",
|
||||
"successMessage": "Meddelande om genomförd åtgärd",
|
||||
"successMessageNotice": "Visas när en användare skapar sitt konto.",
|
||||
"emailMessage": "E-postmeddelande",
|
||||
"emailMessageNotice": "Visas längst ner i e-postmeddelanden."
|
||||
}
|
||||
}
|
||||
5
lang/telegram/en-gb.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "English (GB)"
|
||||
}
|
||||
}
|
||||
11
lang/telegram/en-us.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "English (US)"
|
||||
},
|
||||
"strings": {
|
||||
"startMessage": "Hi!\nEnter your Jellyfin PIN code here to verify your account.",
|
||||
"invalidPIN": "That PIN was invalid, try again.",
|
||||
"pinSuccess": "Success! You can now return to the sign-up page.",
|
||||
"languageMessage": "Note: See available languages with /lang, and set language with /lang <language code>."
|
||||
}
|
||||
}
|
||||