Compare commits

...

558 Commits

Author SHA1 Message Date
Harvey Tindall
a9b11012bc Matrix: Add example images 2021-05-31 20:56:29 +01:00
Harvey Tindall
e7cb1f516b Mention wiki in Telegram/Discord/Matrix settings descriptions 2021-05-31 20:32:16 +01:00
Harvey Tindall
375022ba95 Matrix: Add token generation wizard
Pressing the "+" next to matrix in settings allows you to enter a
homeserver, username and password to enable matrix and generate an
access token.
2021-05-30 23:09:20 +01:00
Harvey Tindall
75fdf6ec3d Matrix: Connect on accounts tab, customizable chat topic 2021-05-30 11:47:41 +01:00
Harvey Tindall
59ebf52fe2 Matrix: Show matrix on accounts page 2021-05-30 00:05:46 +01:00
Harvey Tindall
89fb3fa619 Matrix: Notifications 2021-05-29 21:05:12 +01:00
Harvey Tindall
9bd6abadf4 Matrix: Fix user storage 2021-05-29 19:50:33 +01:00
Harvey Tindall
4e826f4167 Matrix: Store user on sign-up 2021-05-29 18:51:43 +01:00
Harvey Tindall
e97b90d4d7 Matrix: Setup bot, add PIN verification
PIN is verified but not used currently. Works a little different than
the others, you input your matrix user ID and then the PIN is sent to
you. The bot doesn't support E2EE, so the bot being the first one to
message ensures the chat is unencrypted.
2021-05-29 17:43:11 +01:00
Harvey Tindall
fb6256d1ed Telegram: Escape all necessary characters
Fixes #108.
2021-05-25 23:03:13 +01:00
Harvey Tindall
7035a3fe9c Tray: Add button to open logs 2021-05-25 20:16:42 +01:00
Harvey Tindall
62c29d55cc Log output to TEMP/jfa-go.log when Tray enabled
-H=windowsgui completely disables Stdout/Stderr on Windows, so logging
is enabled.
2021-05-25 17:59:41 +01:00
Harvey Tindall
a83dbcf3ab debian/ubuntu, not just debian 2021-05-25 01:33:58 +01:00
Harvey Tindall
e48bdcc45b README: change install section layout
Downloads at the top also now link to parts in the install section.
2021-05-24 22:58:11 +01:00
Harvey Tindall
0b473ef01f don't put .debs on buildrone; link to instructions at top of README 2021-05-24 20:30:31 +01:00
Harvey Tindall
e03525a1d1 separate codenames for stable & unstable
templates don't work in name_template as i though, so this should work
instead.
2021-05-24 19:53:53 +01:00
Harvey Tindall
087172c79e fix package naming to avoid conflicts 2021-05-24 18:46:54 +01:00
Harvey Tindall
8fd919bf04 remove chglog, add steps to upload to apt.hrfee.dev
chglog isn't actually needed. Packages are uploaded as jfa-go(-git) and
jfa-go-tray(-git).
2021-05-24 18:37:26 +01:00
Harvey Tindall
2ad84db482 add inaccurate chglog
not really correct, tagged as v0.3.6 despite the few extra commits.
2021-05-24 16:33:20 +01:00
Harvey Tindall
85536ff79e expand CONTRIBUTING, print if tray enabled on startup 2021-05-24 15:58:43 +01:00
Harvey Tindall
8b62c91d13 Mention TrayIcon deps in README 2021-05-23 23:49:48 +01:00
Harvey Tindall
e7d1693517 Enable updater for Tray builds 2021-05-23 23:20:14 +01:00
Harvey Tindall
e78b4882b3 Fix updater for zip files
Forgot to change this when I switched, oops.
2021-05-23 23:05:40 +01:00
Harvey Tindall
e01144950b Mention Discord in README 2021-05-23 22:41:39 +01:00
Harvey Tindall
86ef665b12 Discord: Try to avoid more race conditions
also added RACE=on to Makefile to enable go's race detector.
2021-05-23 22:26:56 +01:00
Harvey Tindall
f419a57e6d Fixed loaded message, Tray by default 2021-05-23 22:12:47 +01:00
Harvey Tindall
d7e8ec95de add missing perms, fix order 2021-05-23 20:48:17 +01:00
Harvey Tindall
5a9bc1c66f Merge Discord branch
Discord Integration, Accounts UI improvements
2021-05-23 20:25:15 +01:00
Harvey Tindall
1f9af8df89 Discord: Add option to provide server invite
When enabled, a temporary one-use invite is created and shown to the
user on the account creation form.
2021-05-23 19:50:03 +01:00
Harvey Tindall
0676b6c41f Discord: Display channel on account creation form 2021-05-23 17:31:20 +01:00
ClankJake
ac842e6273 translation from Weblate (Portuguese (Brazil))
Currently translated at 100.0% (32 of 32 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/form/pt_BR/
2021-05-23 18:23:21 +02:00
Harvey Tindall
ce8cdced4d Discord: Fix GetUsers, add invite messages
The "Send to" box on the invite tab now accepts username#discriminator,
and a search icon has been added which opens a search window similar to
the one on the accounts tab. DiscordDaemon.GetUsers was also very broken
and wouldn't work with full username#discriminator, that's been fixed.
2021-05-23 16:16:31 +01:00
Harvey Tindall
b8e3fc636c Accounts: Fix cog on telegram when no discord linked
Also, disable telegram & discord if an auth/initialization error occurs.
2021-05-23 14:48:36 +01:00
Harvey Tindall
519a5615cc Accounts: Fix email check on dropdown 2021-05-23 14:35:01 +01:00
Harvey Tindall
168b217553 Discord: fix user links 2021-05-23 14:32:35 +01:00
Harvey Tindall
7d698d63e3 Discord: split discord search into own module
Will also be used for "Send to" on the invite page.
2021-05-23 14:22:18 +01:00
Harvey Tindall
035dbde819 last image 2021-05-23 02:11:48 +01:00
Harvey Tindall
c373d8b2d6 add final oauth tab image 2021-05-23 02:08:02 +01:00
Harvey Tindall
8698c3c6a4 add oauth2 section to bot instructions 2021-05-23 02:03:55 +01:00
Harvey Tindall
0edd2ba68b add settings image for bot setup 2021-05-23 01:51:59 +01:00
Harvey Tindall
b91f0b5a18 Discord: add images for bot creation instructions 2021-05-23 01:38:40 +01:00
Harvey Tindall
24fa841c0d Discord: Wait for non-nil pointer to bot data
While testing others things, I had quite a few nil pointer dereference
errors from accessing bot data right after initializing. A for loop now
waits until the first of the pointers is non-nil, which should
hopefully avoid crashes.
2021-05-23 01:09:03 +01:00
Harvey Tindall
44558b8109 Discord: Remove extra newlines around links
Since links are converted into embeds, links put on their own line often
lead to extra newlines that looks pretty weird. They should now be
stripped.
2021-05-23 01:05:53 +01:00
Harvey Tindall
478b40d0ff Telegram: Escape exclamation marks, remove for images
![alt](link) becomes [alt](link), telegram seems to pick up that they're
images anyway.
2021-05-22 23:38:21 +01:00
Harvey Tindall
8b816dc725 merge translations 2021-05-22 23:26:49 +01:00
Harvey Tindall
81a58f628b Add -H=windowsgui in goreleaser 2021-05-22 23:26:13 +01:00
Harvey Tindall
e98c9b46f1 Accounts: no wrapping for contact dropdown 2021-05-22 23:18:43 +01:00
Harvey Tindall
b3ce7acfcb Accounts: Always inline icons, only one settings cog
Admin chip, email edit bot and contact method cog icon are now always inline.
Only one cog icon is shown now.
2021-05-22 23:05:53 +01:00
Harvey Tindall
9fac79b1f0 Discord: Add users via accounts tab
Doesn't require a PIN like Telegram, as we can access a list of guild
users with the GuildMembers intent set. This has to be enabled under
Bot > Priviliged Gateway intents on the developer portal.
2021-05-22 21:42:15 +01:00
Harvey Tindall
591e3c5ca1 Discord: embed images
![alt](image link) is now converted to an image embed.
2021-05-22 15:32:51 +01:00
Harvey Tindall
35d407afef Discord: remove @ from username 2021-05-22 15:31:25 +01:00
Harvey Tindall
a6447165b7 add email notify enable/disable; remove (de)hyphening
hyphen/dehyphen conflicted with new migration for email contact
preference, and it's been a while since this has been an issue so i've
just commented it out for now.
2021-05-21 22:46:46 +01:00
Malte
23800bb892 Translated using Weblate (German)
Currently translated at 100.0% (7 of 7 strings)

Translation: jfa-go/Password Reset Links
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/password-reset-links/de/
2021-05-21 23:02:50 +02:00
Malte
b47cb91f55 Translated using Weblate (German)
Currently translated at 100.0% (101 of 101 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/setup/de/
2021-05-21 23:02:50 +02:00
Malte
2d9e3fbc1d Translated using Weblate (German)
Currently translated at 100.0% (16 of 16 strings)

Translation: jfa-go/Common Strings
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/common-strings/de/
2021-05-21 23:02:50 +02:00
Malte
bf67e27737 Translated using Weblate (German)
Currently translated at 100.0% (51 of 51 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/emails/de/
2021-05-21 23:02:50 +02:00
Malte
3427c97e3e translation from Weblate (German)
Currently translated at 100.0% (32 of 32 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/form/de/
2021-05-21 23:02:50 +02:00
Malte
81e69a7166 translation from Weblate (German)
Currently translated at 100.0% (156 of 156 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/de/
2021-05-21 23:02:50 +02:00
Malte
564098b9d8 Added translation using Weblate (German) 2021-05-21 23:02:50 +02:00
ClankJake
ec659174fb translation from Weblate (Portuguese (Brazil))
Currently translated at 100.0% (156 of 156 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/pt_BR/
2021-05-21 23:02:50 +02:00
ClankJake
1a42d8280c Translated using Weblate (Portuguese (Brazil))
Currently translated at 93.7% (15 of 16 strings)

Translation: jfa-go/Common Strings
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/common-strings/pt_BR/
2021-05-21 23:02:50 +02:00
ClankJake
b14f10d79d translation from Weblate (Portuguese (Brazil))
Currently translated at 100.0% (32 of 32 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/form/pt_BR/
2021-05-21 23:02:50 +02:00
Cornichon420
ee8facd1bf Translated using Weblate (French)
Currently translated at 100.0% (16 of 16 strings)

Translation: jfa-go/Common Strings
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/common-strings/fr/
2021-05-21 23:02:50 +02:00
Cornichon420
811657b553 Translated using Weblate (French)
Currently translated at 100.0% (51 of 51 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/emails/fr/
2021-05-21 23:02:50 +02:00
Cornichon420
95936f7c29 translation from Weblate (French)
Currently translated at 100.0% (32 of 32 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/form/fr/
2021-05-21 23:02:50 +02:00
Cornichon420
613d4cd9af translation from Weblate (French)
Currently translated at 100.0% (156 of 156 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/fr/
2021-05-21 23:02:50 +02:00
Richard de Boer
7beb3d9974 Translated using Weblate (Dutch)
Currently translated at 100.0% (16 of 16 strings)

Translation: jfa-go/Common Strings
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/common-strings/nl/
2021-05-21 23:02:50 +02:00
Richard de Boer
6f2bb7f0b5 Translated using Weblate (Dutch)
Currently translated at 100.0% (51 of 51 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/emails/nl/
2021-05-21 23:02:50 +02:00
Richard de Boer
315b5fda91 translation from Weblate (Dutch)
Currently translated at 100.0% (32 of 32 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/form/nl/
2021-05-21 23:02:50 +02:00
Richard de Boer
a6aa89e502 translation from Weblate (Dutch)
Currently translated at 100.0% (156 of 156 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/nl/
2021-05-21 23:02:50 +02:00
Harvey Tindall
3bf722c5fe Discord: send links as embeds
Kind of janky but works. This kind of messes up the layout if you write
links in-line.
2021-05-21 21:59:50 +01:00
Harvey Tindall
e931c09a34 add message when web ui is loaded
a lack of output after "Loading routes" was a little confusing.
2021-05-21 21:39:32 +01:00
Harvey Tindall
f8f5f35cc1 PIN verification, notifications, multiple notif providers
Discord, Email & Telegram can be enabled, although email is always
enabled right now (will fix). Also apparently markdown hyperlinks don't
work in Discord, eventually will implement something to convert them to
embeds.
2021-05-21 21:35:25 +01:00
Harvey Tindall
524941da0c fix heading size with sm 2021-05-21 21:10:32 +01:00
Harvey Tindall
22bba922f9 Discord: Add !lang command 2021-05-18 18:41:42 +01:00
Harvey Tindall
d928df7ab2 Discord: Start bot, add !start and pin validity check
The bot should be created by the admin and added to a discord server
mutual to the intended new user(s). On !start in the server,
communication is moved to DMs. Currently !start works, and validity of a
given PIN is checked although nothing it done with this yet.
2021-05-17 23:42:33 +01:00
Harvey Tindall
4b11bbe21f remove leaked telegram token
token has been revoked, but it doesn't look like it was used anyway.
2021-05-17 11:43:58 +01:00
Harvey Tindall
18bcd55972 remove debug println 2021-05-17 01:32:22 +01:00
Harvey Tindall
057f306ed9 hide/ignore ssl_cert when on windows
x509.SystemCertPool is unavailable on windows, so any value is ignored
and the setting is hidden on the web UI.
2021-05-17 01:16:59 +01:00
Harvey Tindall
76bbb3f147 consistent naming for tray builds 2021-05-16 23:02:09 +01:00
Harvey Tindall
0f3ad8bb69 fix generate_ini for multiline descriptions 2021-05-16 23:00:37 +01:00
Harvey Tindall
1d47b9074f change notray/tray naming, add deb/rpm/apk
Since Tray support requires dependencies, it won't be the default for
releases. deb/rpm/apk support may be broken still.
2021-05-16 22:44:04 +01:00
Harvey Tindall
5167fde080 change tar.gz to zip in drone 2021-05-16 21:12:18 +01:00
Harvey Tindall
a62648ee68 fix cross compilation in goreleaser/drone
Necessary for go-autostart to work on windows. Tray will be enabled by
default for x86_64 windows/linux binaries.
2021-05-16 21:01:31 +01:00
Harvey Tindall
5dee414596 add "autostart on login" option to tray 2021-05-16 17:40:03 +01:00
Harvey Tindall
8cf9b1f905 add basic tray functionality
enable with `make TRAY=on ...`. Cross compilation apparently should work
from linux to linux & windows.
2021-05-16 16:23:28 +01:00
Harvey Tindall
6bf1920160 merge dependabot bump 2021-05-16 15:00:30 +01:00
Harvey Tindall
33f8070e57 cleanup; fix stripping with DEBUG=on 2021-05-16 15:00:13 +01:00
Harvey Tindall
4d2a018032 Merge pull request #98 from hrfee/dependabot/npm_and_yarn/lodash-4.17.21
Bump lodash from 4.17.20 to 4.17.21
2021-05-14 14:48:41 +01:00
dependabot[bot]
ca7fb540ee Bump lodash from 4.17.20 to 4.17.21
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.20 to 4.17.21.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.20...4.17.21)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-11 21:24:34 +00:00
ClankJake
beb0712ce9 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (101 of 101 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/setup/pt_BR/
2021-05-09 20:59:31 +02:00
woosade
a081b14794 Translated using Weblate (Spanish)
Currently translated at 100.0% (7 of 7 strings)

Translation: jfa-go/Password Reset Links
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/password-reset-links/es/
2021-05-09 20:59:30 +02:00
woosade
e416acf6bd translation from Weblate (Spanish)
Currently translated at 100.0% (152 of 152 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/es/
2021-05-09 20:59:30 +02:00
woosade
bf94f76509 Translated using Weblate (Spanish)
Currently translated at 100.0% (101 of 101 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/setup/es/
2021-05-09 20:59:30 +02:00
Richard de Boer
ac239a309c translation from Weblate (Dutch)
Currently translated at 100.0% (152 of 152 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/nl/
2021-05-09 20:59:30 +02:00
Richard de Boer
0f12586166 Translated using Weblate (Dutch)
Currently translated at 100.0% (101 of 101 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/setup/nl/
2021-05-09 20:59:30 +02:00
Cornichon420
b1b50ce561 Translated using Weblate (French)
Currently translated at 100.0% (101 of 101 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/setup/fr/
2021-05-09 20:59:30 +02:00
Cornichon420
8e2bf48ab4 Translated using Weblate (French)
Currently translated at 100.0% (13 of 13 strings)

Translation: jfa-go/Common Strings
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/common-strings/fr/
2021-05-09 20:59:30 +02:00
Cornichon420
6ec5022a0d translation from Weblate (French)
Currently translated at 100.0% (28 of 28 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/form/fr/
2021-05-09 20:59:30 +02:00
Cornichon420
ef97e0ac76 translation from Weblate (French)
Currently translated at 100.0% (152 of 152 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/fr/
2021-05-09 20:59:30 +02:00
Harvey Tindall
30736a055d add example bot settings for wiki 2021-05-08 16:37:40 +01:00
Harvey Tindall
d0905a29be add example bot creation for wiki 2021-05-08 16:29:16 +01:00
Harvey Tindall
fe5cf69b7a Merge Telegram support
For #94.
2021-05-08 16:15:41 +01:00
Harvey Tindall
c560ec0f9f Merge branch 'main' into telegram 2021-05-08 16:08:20 +01:00
Harvey Tindall
71554e0c85 Telegram: Change user's contact method in accounts
By clicking the cog next to the telegram username, one can select
whether to contact through telegram or email.
2021-05-08 15:53:42 +01:00
Harvey Tindall
0efd7c5718 Telegram: add language files
somehow these were included in the .gitignore.
2021-05-07 23:45:53 +01:00
Harvey Tindall
901ad7529e mention wiki in telegram settings description 2021-05-07 23:36:46 +01:00
Harvey Tindall
b64bcc9738 include telegram verif in images 2021-05-07 23:30:32 +01:00
Harvey Tindall
fddb7b7584 Mention telegram in readme 2021-05-07 23:18:44 +01:00
Harvey Tindall
b91302ddf8 Invite: fix "none yet" message on users created 2021-05-07 22:41:51 +01:00
Harvey Tindall
ea0293bd4e Split some settings into new "messages" section
Most email dependant sections now depend on this. Also renamed more
email things.
2021-05-07 21:53:29 +01:00
Harvey Tindall
51f2f4cc6a Telegram: close updates channel on restart
Also removed some references to email.
2021-05-07 18:29:56 +01:00
Harvey Tindall
2d93b3b7ee Telegram: Allow admin to add telegram contact
Works in the same way as on the form, but can now be done in the
accounts tab.
2021-05-07 18:20:35 +01:00
Harvey Tindall
0f41d1e6cf Telegram: Display username on accounts tab 2021-05-07 17:01:22 +01:00
Harvey Tindall
36edd4ab0d Telegram: Use markdown for custom emails/announcements
Had no idea telegram supported this, pretty cool.
2021-05-07 16:33:44 +01:00
Harvey Tindall
716d6a931a Telegram: Send messages via telegram
Most messages are now sent as plaintext via telegram when suitable.
2021-05-07 16:06:47 +01:00
Harvey Tindall
72bf280e2d telegram: Fix UI and store useful Telegram info
Creation now works, and language preferences made before signup are
kept. telegram file storage now uses the Jellyfin ID as a key, which
makes much more sense. Also added radios to select preferred notification
method (email/telegram) as well, which the admin will soon be able to
change also.
2021-05-07 14:32:51 +01:00
Harvey Tindall
326c2cf70a modal: use arrow function to avoid 'this' naming collision 2021-05-07 14:30:30 +01:00
Harvey Tindall
2816c6277d modal: add onopen/onclose 2021-05-07 13:22:07 +01:00
Harvey Tindall
99875b9176 almost complete telegram user verification
When signing up, the user is given a pin code which they send to a
telegram bot. This provides user verification, but more importantly
allows the bot to message the user, as the Telegram API requires the
user to interact with the bot before it can do the opposite.

The bot should recognize the correct language, but a /lang command is
also provided to change it.

The verification process is pretty much functional but ui is still
broken, and it isn't properly integrated yet.
2021-05-07 01:08:12 +01:00
Harvey Tindall
0e21942cd6 add hard restart for updates on *nix
reincarnates app.Restart() removed in
bbb0568cc4 as app.HardRestart().
2021-05-03 20:08:23 +01:00
Harvey Tindall
b2b5083102 fix checkCheckCount on accounts reload 2021-05-03 18:55:46 +01:00
Harvey Tindall
c0f316d049 add preview to Announcements 2021-05-03 18:35:27 +01:00
Harvey Tindall
2c6d08319b add typechecking step to Makefile when DEBUG=on 2021-05-03 18:32:56 +01:00
Harvey Tindall
5d8f139356 fix race condition; rename route functions; fix swagger params
fix race condition when notifying of invite expiry, rename custom email
related functions as to reduce confusion, and add proper path params for
some swagger routes. Also moved some stuff around in api.go.
2021-05-02 20:42:37 +01:00
Harvey Tindall
87ef71b415 lowercase lang 2021-05-02 15:25:09 +01:00
André Cruz
cf99ae880c Translated using Weblate (Spanish)
Currently translated at 100.0% (6 of 6 strings)

Translation: jfa-go/Password Reset Links
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/password-reset-links/es/
2021-05-02 16:23:10 +02:00
André Cruz
8e86078394 Translated using Weblate (Spanish)
Currently translated at 100.0% (51 of 51 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/emails/es/
2021-05-02 16:23:10 +02:00
André Cruz
beea903879 translation from Weblate (Spanish)
Currently translated at 100.0% (151 of 151 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/es/
2021-05-02 16:23:10 +02:00
André Cruz
c5e4c5d509 Translated using Weblate (Spanish)
Currently translated at 100.0% (13 of 13 strings)

Translation: jfa-go/Common Strings
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/common-strings/es/
2021-05-02 16:23:10 +02:00
André Cruz
fac951c733 Translated using Weblate (Spanish)
Currently translated at 100.0% (98 of 98 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/setup/es/
2021-05-02 16:23:10 +02:00
Cornichon420
83449f3332 Translated using Weblate (French)
Currently translated at 100.0% (51 of 51 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/emails/fr/
2021-05-02 16:23:10 +02:00
Cornichon420
2a9fc8c7a5 translation from Weblate (French)
Currently translated at 88.0% (133 of 151 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/fr/
2021-05-02 16:23:10 +02:00
André Cruz
f8d4f79271 Translated using Weblate (Spanish)
Currently translated at 100.0% (98 of 98 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/setup/es/
2021-05-02 16:23:10 +02:00
André Cruz
bc466d0c6f Added translation using Weblate (Spanish) 2021-05-02 16:23:10 +02:00
Harvey Tindall
382a0f4c3c add donate button to about 2021-05-02 15:16:28 +01:00
Harvey Tindall
488c2f5df5 fix broken url in welcome email 2021-05-02 14:44:19 +01:00
Harvey Tindall
43effd0c32 add reset link option to setup 2021-05-02 14:15:03 +01:00
Harvey Tindall
af61549bf1 ombi: reset password when using pwr links
When password reset links are enabled, the ombi password will be reset
to the PIN along with Jellyfin.
2021-05-02 13:23:59 +01:00
Harvey Tindall
22a0d8925d Remove unused typescript, update config readme 2021-05-02 13:23:33 +01:00
Harvey Tindall
59a014f681 fix title for invite emails 2021-05-02 12:50:04 +01:00
Harvey Tindall
9944cc2db9 refactor; move logger to module 2021-05-01 00:13:57 +01:00
Harvey Tindall
570e3a1e54 fix en-es name and filename 2021-04-30 13:54:53 +01:00
woosade
a9bde40661 translation from Weblate (Spanish)
Currently translated at 100.0% (151 of 151 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/es/
2021-04-29 23:54:04 +02:00
woosade
b03a185e88 Translated using Weblate (Spanish)
Currently translated at 100.0% (98 of 98 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/setup/es/
2021-04-29 23:54:03 +02:00
woosade
e450587eea translation from Weblate (Portuguese (Brazil))
Currently translated at 100.0% (151 of 151 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/pt_BR/
2021-04-29 23:54:03 +02:00
Richard de Boer
30a529baac translation from Weblate (Dutch)
Currently translated at 100.0% (151 of 151 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/nl/
2021-04-29 23:54:03 +02:00
woosade
adbb74f56b Translated using Weblate (Spanish)
Currently translated at 100.0% (98 of 98 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/setup/es/
2021-04-28 15:15:40 +02:00
woosade
223b4df172 translation from Weblate (Spanish)
Currently translated at 100.0% (28 of 28 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/form/es/
2021-04-28 15:15:40 +02:00
woosade
44dc315914 Translated using Weblate (Spanish)
Currently translated at 100.0% (51 of 51 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/emails/es/
2021-04-28 15:15:40 +02:00
woosade
c959e2ce4d translation from Weblate (Spanish)
Currently translated at 100.0% (150 of 150 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/es/
2021-04-28 15:15:40 +02:00
woosade
57b10dd514 Translated using Weblate (Spanish)
Currently translated at 100.0% (13 of 13 strings)

Translation: jfa-go/Common Strings
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/common-strings/es/
2021-04-28 15:15:40 +02:00
woosade
9da0f89613 Added translation using Weblate (Spanish) 2021-04-28 15:15:40 +02:00
woosade
4104cb334e add translation from Weblate (Spanish) 2021-04-28 15:15:40 +02:00
woosade
94067a1ec2 Added translation using Weblate (Spanish) 2021-04-28 15:15:40 +02:00
woosade
3e9da3baf7 add translation from Weblate (Spanish) 2021-04-28 15:15:40 +02:00
woosade
6129305b2c Added translation using Weblate (Spanish) 2021-04-28 15:15:40 +02:00
ClankJake
7165eb1f59 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (51 of 51 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/emails/pt_BR/
2021-04-28 15:15:40 +02:00
ClankJake
a4820de423 translation from Weblate (Portuguese (Brazil))
Currently translated at 100.0% (150 of 150 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/pt_BR/
2021-04-28 15:15:40 +02:00
Marketos Damigos
0c09f3b05f Translated using Weblate (Greek)
Currently translated at 100.0% (51 of 51 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/emails/el/
2021-04-28 15:15:40 +02:00
Marketos Damigos
269d67f071 translation from Weblate (Greek)
Currently translated at 100.0% (150 of 150 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/el/
2021-04-28 15:15:39 +02:00
Richard de Boer
bdc0c0ffa2 Translated using Weblate (Dutch)
Currently translated at 100.0% (51 of 51 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/emails/nl/
2021-04-28 15:15:39 +02:00
Richard de Boer
c00f5f4330 translation from Weblate (Dutch)
Currently translated at 100.0% (150 of 150 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/nl/
2021-04-28 15:15:39 +02:00
Harvey Tindall
a2c344de83 add shorthand flag names
along with an ugly wrapper for the help message that merges the
descriptions for the short & long versions.
2021-04-24 23:54:56 +01:00
Harvey Tindall
886ae64feb add "systemd" command to generate a .service file
never got around to adding this from jellyfin-accounts for some reason.
2021-04-24 18:54:31 +01:00
Harvey Tindall
90a2c1f2e7 Fix email editor for other email types 2021-04-22 19:16:41 +01:00
Harvey Tindall
d772e43e44 merge language changes 2021-04-15 15:34:52 +01:00
Harvey Tindall
8fdab39b18 use templateEmail and show conditionals in editor 2021-04-15 15:34:17 +01:00
Harvey Tindall
f7d2771263 add email templater with basic if statements
at this point I really should've just used text/template, but I guess
this way compatibility is kept with existing custom emails. If statement
works as so:

{if variable}variable was true{endif}
{if !variable}variable was false{endif}

no else yet, just do as above (two if statements).
2021-04-14 23:58:54 +01:00
ClankJake
e8b1cca9ca translation from Weblate (Portuguese (Brazil))
Currently translated at 100.0% (140 of 140 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/pt_BR/
2021-04-14 19:15:43 +02:00
Richard de Boer
d4d7219801 translation from Weblate (Dutch)
Currently translated at 100.0% (140 of 140 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/nl/
2021-04-14 19:15:43 +02:00
Harvey Tindall
3273607fc3 translation: add fallback option to langMeta
If set to a language code (e.g fr-fr), any missing strings will be
filled in from that language (if possible) rather than from the default
en-us. Currently not used, but could be useful in the future for
variations of the same language.
2021-04-13 18:34:13 +01:00
Harvey Tindall
55e21f8be3 accounts: add user enable/disable & emails 2021-04-12 21:28:36 +01:00
ClankJake
dafb439a7d Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (45 of 45 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/emails/pt_BR/
2021-04-12 18:27:42 +02:00
Richard de Boer
ab94de2f95 Translated using Weblate (Dutch)
Currently translated at 100.0% (45 of 45 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/emails/nl/
2021-04-12 18:27:42 +02:00
Harvey Tindall
3dc0df0ac2 fix user expiry when only month field set 2021-04-09 13:35:46 +01:00
Harvey Tindall
d701c5f27d add months field to invites & expiry 2021-04-08 20:43:01 +01:00
Harvey Tindall
a8f71c83da store language preference as cookie 2021-04-08 16:03:46 +01:00
Harvey Tindall
7a3e0d60f9 add expiry to welcome email, add dummy emailer for debugging
the "yourAccountWillExpire" has also been added to the editor for #81.
To use the dummy emailer, set [email]/method to "dummy".
2021-04-08 14:20:13 +01:00
Harvey Tindall
2687af31ca updater: immediately store executable
for some reason I kept the response body and downloaded file in memory,
which led to timeouts and failed updates.
2021-04-07 18:17:18 +01:00
Harvey Tindall
d51a6abb02 remove cl.md 2021-04-07 17:45:31 +01:00
Harvey Tindall
374ffbf01f fix incomplete lang patching, add en-gb stub
en-gb is empty, so it's patched with en-us strings. Added so DD/MM/YY
date formatting was possible in the ui.
2021-04-07 17:42:15 +01:00
Harvey Tindall
871bc9f396 use proper date formatting on form for expiry 2021-04-07 15:17:15 +01:00
Harvey Tindall
66b7df7cde use selected language for time format, add manual selector
You can now choose between 12h and 24h time in the top left language
menu. Your preference is stored by the browser for future visits.
2021-04-07 15:09:44 +01:00
Harvey Tindall
bc76770ca4 move 12h/24h time strings to common 2021-04-07 15:09:25 +01:00
Harvey Tindall
7196361cf6 (hopefully) get proper locale from browser 2021-04-07 14:05:17 +01:00
Harvey Tindall
3e73d16cce merge language changes 2021-04-06 21:30:14 +01:00
Harvey Tindall
3f8414c70a use unix timestamp for inv created & usedBy
usedBy is still stored as a string in invites.json to cope with existing
invites with times stored formatted. knz/strtime requires cgo for
strptime, so it has been replaced with the native itchyny/timefmt-go.
2021-04-06 21:25:44 +01:00
Harvey Tindall
6ec2186bdf switch accounts tab to unix times
should now respect the client's locale.
2021-04-06 20:53:30 +01:00
ClankJake
6dd575b276 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (44 of 44 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/emails/pt_BR/
2021-04-06 19:49:18 +02:00
JoshiJoshiJoshi
1a98946d71 Translated using Weblate (German)
Currently translated at 100.0% (100 of 100 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/setup/de/
2021-04-06 19:49:18 +02:00
ClankJake
8922549bdb Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (11 of 11 strings)

Translation: jfa-go/Common Strings
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/common-strings/pt_BR/
2021-04-06 19:49:18 +02:00
Richard de Boer
173b49aeb7 Translated using Weblate (Dutch)
Currently translated at 100.0% (11 of 11 strings)

Translation: jfa-go/Common Strings
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/common-strings/nl/
2021-04-06 19:49:18 +02:00
JoshiJoshiJoshi
eee6046465 Translated using Weblate (German)
Currently translated at 100.0% (11 of 11 strings)

Translation: jfa-go/Common Strings
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/common-strings/de/
2021-04-06 19:49:18 +02:00
JoshiJoshiJoshi
b76011be4f translation from Weblate (German)
Currently translated at 100.0% (28 of 28 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/form/de/
2021-04-06 19:49:18 +02:00
Richard de Boer
3d93d79b0b Translated using Weblate (Dutch)
Currently translated at 100.0% (44 of 44 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/emails/nl/
2021-04-06 19:49:18 +02:00
Harvey Tindall
7dcc9b20a1 clear user cache when user expires 2021-04-06 18:39:12 +01:00
Harvey Tindall
754b956206 remove extra logs 2021-04-06 18:32:32 +01:00
Harvey Tindall
47ac505cac shutdown your background workers!
I believe everything #74 was caused by not shutting down the userDaemon
when we do a pseudo-restart. shutdown of it and the invite daemon are
now deferred so this should fix any problems and reduce log spam.
2021-04-06 18:12:06 +01:00
Harvey Tindall
e6e5231f63 add extra logging 2021-04-06 18:02:15 +01:00
Harvey Tindall
78049d4a33 hyphenate/dehyphenate users.json if necessary
doubt this would have caused problems anyway but why not.
2021-04-06 15:46:28 +01:00
Harvey Tindall
8a6cfe0b4d disallow negative values in ExtendExpiry, fix nil map err 2021-04-06 14:00:32 +01:00
Harvey Tindall
afedc78113 only load users if they don't exist already
another guess for #77.
2021-04-06 13:53:07 +01:00
Harvey Tindall
76b822213e add more error logging; mutex for app.storage.users 2021-04-06 13:44:52 +01:00
Harvey Tindall
ab3d5f3321 fix logging for expiry extension
also delete expiries for users that no longer exist.
2021-04-06 13:31:42 +01:00
Harvey Tindall
e1d42c8a87 Update CONTRIBUTING.md, mb 0.3.3
One last missing field added for #76.
2021-04-05 16:34:47 +01:00
Harvey Tindall
f53c852a4d bump mb to v0.3.2
includes missing struct fields for user Policy, fixes #76.
2021-04-05 15:07:30 +01:00
Harvey Tindall
aaea889e47 use apt-get in drone.yml 2021-04-03 21:38:26 +01:00
Harvey Tindall
bf98c74ecf Merge pull request #75 from Toucan-Sam/patch-1
Fix docker link in README.md
2021-04-03 21:37:54 +01:00
Toucan-Sam
fcadabd339 Fix docker link in README.md 2021-04-04 08:32:38 +12:00
Harvey Tindall
2a0edeb3c5 bump mediabrowser version, more consistent logs
uses descriptive errors added in mb v0.2.0. Also improved
the consistency of logs in api.go/main.go.
2021-04-02 22:13:04 +01:00
Harvey Tindall
30f16e7207 email: use strconv.Itoa instead of sprintf 2021-04-02 15:56:34 +01:00
Harvey Tindall
dbe7e2e659 remove ts-debug 2021-04-01 14:33:57 +01:00
Harvey Tindall
e16f05b130 use build constraints for embed, clean up makefile
internal-files/external-files and compile-debug are gone, the
environment variables INTERNAL=on/off and DEBUG=on/off replace them.
2021-04-01 14:22:11 +01:00
Harvey Tindall
07573a515a merge translation 2021-04-01 12:58:06 +01:00
Harvey Tindall
b3a2de50cf hide no_username support message on setup
fixes #74.
2021-04-01 12:56:47 +01:00
Marketos Damigos
5388d3d4c0 Translated using Weblate (Greek)
Currently translated at 100.0% (11 of 11 strings)

Translation: jfa-go/Common Strings
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/common-strings/el/
2021-03-31 21:18:01 +02:00
Marketos Damigos
c392d48174 Translated using Weblate (Greek)
Currently translated at 100.0% (44 of 44 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/emails/el/
2021-03-31 21:18:00 +02:00
Marketos Damigos
967fab3411 Translated using Weblate (Greek)
Currently translated at 100.0% (100 of 100 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/setup/el/
2021-03-31 14:54:34 +02:00
Marketos Damigos
d7845b78f6 Translated using Weblate (Greek)
Currently translated at 100.0% (43 of 43 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/emails/el/
2021-03-31 14:54:34 +02:00
Marketos Damigos
a253858625 translation from Weblate (Greek)
Currently translated at 100.0% (140 of 140 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/el/
2021-03-31 14:54:34 +02:00
Marketos Damigos
ad1aae16e3 translation from Weblate (Greek)
Currently translated at 100.0% (28 of 28 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/form/el/
2021-03-31 14:54:34 +02:00
Harvey Tindall
9370913ace add password reset link option
When enabled (in Settings > Password Resets), a magic link will be sent
instead of a PIN when the user tries reset their password. By doing
this the user doesn't have to keep the Jellyfin tab open to enter the
code.
2021-03-30 22:41:28 +01:00
Harvey Tindall
dcd2e234e8 move "copy" string to common, add "copied"
for a new password reset feature.
2021-03-30 21:16:24 +01:00
Harvey Tindall
762dac2581 move mediabrowser to separate repo 2021-03-29 21:49:46 +01:00
Harvey Tindall
1cf8d3037b remove dependency on common from mediabrowser 2021-03-29 20:57:13 +01:00
Harvey Tindall
40808bdcb9 merge language changes 2021-03-29 20:54:06 +01:00
Harvey Tindall
2451d69341 rewrite lang.go format and templateString
surprisingly not much faster than the originals.
2021-03-27 16:07:22 +00:00
virusperfect
e449853568 Translated using Weblate (German)
Currently translated at 100.0% (100 of 100 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/setup/de/
2021-03-27 00:19:06 +01:00
virusperfect
2082e960c2 Translated using Weblate (German)
Currently translated at 100.0% (43 of 43 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/emails/de/
2021-03-27 00:19:06 +01:00
virusperfect
7b2a083f98 translation from Weblate (German)
Currently translated at 100.0% (28 of 28 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/form/de/
2021-03-27 00:19:06 +01:00
virusperfect
270143a8f6 translation from Weblate (German)
Currently translated at 100.0% (140 of 140 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/de/
2021-03-27 00:19:06 +01:00
ClankJake
766b69d95e translation from Weblate (Portuguese (Brazil))
Currently translated at 100.0% (140 of 140 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/pt_BR/
2021-03-27 00:19:06 +01:00
ClankJake
f5addc4947 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (100 of 100 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/setup/pt_BR/
2021-03-27 00:19:06 +01:00
ClankJake
55eb59c526 translation from Weblate (Portuguese (Brazil))
Currently translated at 100.0% (28 of 28 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/form/pt_BR/
2021-03-27 00:19:06 +01:00
Richard de Boer
679cac4dbd Translated using Weblate (Dutch)
Currently translated at 100.0% (100 of 100 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/setup/nl/
2021-03-27 00:19:06 +01:00
Harvey Tindall
a0a25d64f1 rewrite stripmd, fix some typos
doesn't work any better, but more efficient and doesn't require
eyebleach after viewing.
2021-03-26 23:13:19 +00:00
Harvey Tindall
9875458b01 rewrite time unmarshaler for mediabrowser
Last ditch effort for #69, removes quotes and trailing Z's manually and
also removes nanoseconds since they're useless.
2021-03-23 21:59:41 +00:00
Harvey Tindall
f0dccc58aa separate pprof from debug mode
enabled with -pprof now.
2021-03-23 21:59:04 +00:00
Harvey Tindall
636bc22d52 reimplement Lshortfile for log wrapper
Fixes all debug messages having "logger:<line>:" instead of the actual
caller.
2021-03-23 21:57:53 +00:00
Harvey Tindall
fc6b6a9c6b Fix time parser for "ZZ" prefix
I think this means UTC-08:00, but this just strips it since time
handling is pretty naïve already.
2021-03-23 16:10:25 +00:00
Harvey Tindall
1a6d78352c add comments, fix user expiry log spam
now actually removes the already deleted user from the expiry list.
2021-03-21 22:50:33 +00:00
Harvey Tindall
e351c35cc8 use banner class on banner in about 2021-03-21 00:59:51 +00:00
Harvey Tindall
618cc32a17 hide updates from settings when disabled at build-time 2021-03-20 23:32:32 +00:00
Harvey Tindall
a8bf670697 dont log updates when disabled 2021-03-20 23:20:07 +00:00
Harvey Tindall
0bdf8ad6ce put upload.py in parent dir 2021-03-20 23:16:54 +00:00
Harvey Tindall
8f65e2e968 fix drone.yml for stable docker 2021-03-20 23:13:03 +00:00
Harvey Tindall
0d3f96c3a7 fix button height on accounts tab & expiry types on mobile 2021-03-20 22:16:24 +00:00
Harvey Tindall
cfa7947020 wrap items in accounts header
fixes mobile layout.
2021-03-20 19:23:54 +00:00
Harvey Tindall
b91de3f319 update images and readme 2021-03-20 19:04:26 +00:00
Harvey Tindall
1704ae8cb1 fix language link color on dark theme 2021-03-20 18:24:35 +00:00
Richard de Boer
50c6e6031d translation from Weblate (Dutch)
Currently translated at 100.0% (140 of 140 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/nl/
2021-03-20 19:02:09 +01:00
Harvey Tindall
de92516d52 add updates section to setup 2021-03-20 18:00:01 +00:00
Harvey Tindall
cd67d3e7ab merge translation 2021-03-18 16:49:17 +00:00
Harvey Tindall
c556878f11 hide password resets on setup when emby selected 2021-03-18 16:47:13 +00:00
Richard de Boer
3af4607171 translation from Weblate (Dutch)
Currently translated at 100.0% (139 of 139 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/nl/
2021-03-15 23:52:09 +01:00
Harvey Tindall
111533fa2d add advanced setting type with toggle in settings 2021-03-15 22:51:17 +00:00
Harvey Tindall
5dc0a68b44 merge translations 2021-03-15 21:58:36 +00:00
Harvey Tindall
43e5bbbe21 add option to trust specific cert for SMTP 2021-03-15 21:57:42 +00:00
ClankJake
42921f6a3e translation from Weblate (Portuguese (Brazil))
Currently translated at 99.2% (138 of 139 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/pt_BR/
2021-03-14 17:28:10 +01:00
Harvey Tindall
5892899114 thread compile_mjml 2021-03-13 17:05:59 +00:00
Peter Wickenberg
4404c84e7f Translated using Weblate (Swedish)
Currently translated at 100.0% (43 of 43 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/emails/sv/
2021-03-13 17:48:06 +01:00
Peter Wickenberg
a86be55b5c translation from Weblate (Swedish)
Currently translated at 100.0% (130 of 130 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/sv/
2021-03-13 17:48:06 +01:00
Peter Wickenberg
5eea72a579 translation from Weblate (Swedish)
Currently translated at 100.0% (28 of 28 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/form/sv/
2021-03-13 17:48:06 +01:00
Harvey Tindall
03247ddef8 Add accounts search 2021-03-13 14:26:29 +00:00
Harvey Tindall
e6e5b0f3cf respect browser/os dark mode preference 2021-03-10 19:42:40 +00:00
Harvey Tindall
9b977bafbf add other funding method 2021-03-09 18:45:28 +00:00
Harvey Tindall
77f755e43c fix dropdown colors in dark mode on chrome 2021-03-09 18:15:14 +00:00
Harvey Tindall
30bef15855 Trim commit before comparing in IsNew()
Fixes the current version appearing as an update. Also fixed error
handling when no update is available, which obviously hadn't previously
been experienced.
2021-03-09 15:52:15 +00:00
Harvey Tindall
7bd8fadf76 IsNew() compares commit, not version 2021-03-07 17:24:45 +00:00
Harvey Tindall
21490faa9e fix IsNew() func, include LICENSE in goreleaser 2021-03-07 16:45:35 +00:00
Harvey Tindall
f685582e1a run upload.py in git directory 2021-03-07 16:27:15 +00:00
Harvey Tindall
f792166523 use locally stored buildrone key bcs ssh is broken 2021-03-07 16:15:31 +00:00
Harvey Tindall
7c0754a70c fix buildrone env 2021-03-07 16:07:55 +00:00
Harvey Tindall
2f33580f32 remove testing goreleaser script, oops 2021-03-07 15:55:28 +00:00
Harvey Tindall
eb8f2777ae fix naming conflict with goreleaser, add buildrone key to other steps 2021-03-07 15:54:32 +00:00
Harvey Tindall
92332206f0 add basic update functionality
If enabled, jfa-go pings buildrone (hosted at builds.hrfee.pw) every 30
min for new updates. If there is one, it gets information (and if
applicable, a binary) from the appropriate source (buildrone, github, or
dockerhub) and displays it on the admin page. You can switch update
channels between stable and unstable. For binary releases, updates are
downloaded automatically and installed when the user presses update.

Since this obviously introduces some "phone-home" functionality into
jfa-go, I just want to say IPs are not and will not be logged by
buildrone, although I may later introduce functionality to give a rough
idea of the number of users (again, no IPs stored). The whole thing can
also be turned off in settings.
2021-03-07 15:23:44 +00:00
ClankJake
9787fce275 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (43 of 43 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/emails/pt_BR/
2021-03-02 16:34:29 +01:00
ClankJake
1c67b06c27 translation from Weblate (Portuguese (Brazil))
Currently translated at 98.4% (128 of 130 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/pt_BR/
2021-03-02 16:34:29 +01:00
ClankJake
88eab75e30 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (95 of 95 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/setup/pt_BR/
2021-03-02 16:34:29 +01:00
ClankJake
6c5f776a7a translation from Weblate (Portuguese (Brazil))
Currently translated at 100.0% (28 of 28 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/form/pt_BR/
2021-03-02 16:34:29 +01:00
Richard de Boer
ca0c56e748 Translated using Weblate (Dutch)
Currently translated at 100.0% (43 of 43 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/emails/nl/
2021-03-02 16:34:28 +01:00
Richard de Boer
e29e0ddb5b translation from Weblate (Dutch)
Currently translated at 100.0% (28 of 28 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/form/nl/
2021-03-02 16:34:28 +01:00
Richard de Boer
7ce75c271c translation from Weblate (Dutch)
Currently translated at 100.0% (130 of 130 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/nl/
2021-03-02 16:34:28 +01:00
Harvey Tindall
884493e7aa add download links at top, mention jfa-go-bin 2021-03-02 01:30:08 +00:00
Harvey Tindall
bd05a4b35a include LICENSE in build, display in about tab
Also fixes last commit, user cache wasn't refreshed in ApplySettings, is
now.
2021-03-01 00:32:09 +00:00
Harvey Tindall
fa7da1b23f Don't use cache to ApplySettings and CreateProfile
also use a wrapper function to set default settings in config.go so it's
less ugly.
2021-02-28 18:26:22 +00:00
Harvey Tindall
1ec5d2ca3f add disabled badge, extend expiry button to accounts 2021-02-28 17:52:24 +00:00
Harvey Tindall
1e9d184508 implement user expiry functionality
All works now, but i'll add a field on the accounts tab for users with
an expiry, as well as a 'disabled' badge.
2021-02-28 15:41:06 +00:00
Harvey Tindall
2934832a98 implement frontend for user expiry/duration
this will add an optional validity period to users, where their account
will be disabled (or deleted) a specified amount of time after they
created it.
2021-02-28 00:44:28 +00:00
Harvey Tindall
3635b6a367 lowercase lang names 2021-02-24 21:49:29 +00:00
Peter Wickenberg
2b97850eb2 Translated using Weblate (Swedish)
Currently translated at 100.0% (95 of 95 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/setup/sv/
2021-02-24 22:48:17 +01:00
Peter Wickenberg
c1d1b0e560 Translated using Weblate (Swedish)
Currently translated at 100.0% (39 of 39 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/emails/sv/
2021-02-24 22:48:17 +01:00
Peter Wickenberg
e1d9a00d67 Translated using Weblate (Swedish)
Currently translated at 100.0% (9 of 9 strings)

Translation: jfa-go/Common Strings
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/common-strings/sv/
2021-02-24 22:48:17 +01:00
Peter Wickenberg
35aa37e10e translation from Weblate (Swedish)
Currently translated at 100.0% (118 of 118 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/sv/
2021-02-24 22:48:17 +01:00
Peter Wickenberg
e38c470fb9 translation from Weblate (Swedish)
Currently translated at 100.0% (27 of 27 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/form/sv/
2021-02-24 22:48:17 +01:00
Peter Wickenberg
edd4584136 Translated using Weblate (Swedish)
Currently translated at 100.0% (95 of 95 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/setup/sv/
2021-02-24 15:59:00 +01:00
Peter Wickenberg
d7a84c1982 Translated using Weblate (Swedish)
Currently translated at 100.0% (39 of 39 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/emails/sv/
2021-02-24 15:59:00 +01:00
Peter Wickenberg
fe86b8a7d0 Translated using Weblate (Swedish)
Currently translated at 100.0% (9 of 9 strings)

Translation: jfa-go/Common Strings
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/common-strings/sv/
2021-02-24 15:59:00 +01:00
Peter Wickenberg
01f290b459 translation from Weblate (Swedish)
Currently translated at 100.0% (118 of 118 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/sv/
2021-02-24 15:59:00 +01:00
Peter Wickenberg
9a398e9291 translation from Weblate (Swedish)
Currently translated at 100.0% (27 of 27 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/form/sv/
2021-02-24 15:59:00 +01:00
Peter Wickenberg
1fbd11dbe8 Translated using Weblate (Swedish)
Currently translated at 100.0% (39 of 39 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/emails/sv/
2021-02-24 15:41:33 +01:00
Peter Wickenberg
68b26f8301 Translated using Weblate (Swedish)
Currently translated at 100.0% (9 of 9 strings)

Translation: jfa-go/Common Strings
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/common-strings/sv/
2021-02-24 15:41:32 +01:00
Peter Wickenberg
6877f3975e translation from Weblate (Swedish)
Currently translated at 100.0% (118 of 118 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/sv/
2021-02-24 15:41:32 +01:00
Peter Wickenberg
6a11ed5622 translation from Weblate (Swedish)
Currently translated at 100.0% (27 of 27 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/form/sv/
2021-02-24 15:41:31 +01:00
Peter Wickenberg
53bec00a7e Translated using Weblate (Swedish)
Currently translated at 100.0% (95 of 95 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/setup/sv/
2021-02-24 15:41:31 +01:00
Peter Wickenberg
c616ab324d Added translation using Weblate (Swedish) 2021-02-23 23:33:04 +01:00
Peter Wickenberg
7e21eb87db Added translation using Weblate (Swedish) 2021-02-23 23:32:52 +01:00
Peter Wickenberg
98cd33da05 Added translation using Weblate (Swedish) 2021-02-23 23:32:40 +01:00
Peter Wickenberg
d520694e12 add translation from Weblate (Swedish) 2021-02-23 23:32:30 +01:00
Peter Wickenberg
3c4800efa8 add translation from Weblate (Swedish) 2021-02-23 23:25:42 +01:00
mezzovide
bd227842d2 translation from Weblate (Indonesian)
Currently translated at 100.0% (118 of 118 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/id/
2021-02-22 18:53:04 +01:00
mezzovide
f47bf762ac Translated using Weblate (Indonesian)
Currently translated at 100.0% (39 of 39 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/emails/id/
2021-02-22 18:53:04 +01:00
ClankJake
1342208980 translation from Weblate (Portuguese (Brazil))
Currently translated at 100.0% (118 of 118 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/pt_BR/
2021-02-22 18:53:03 +01:00
virusperfect
c8a9b15b4e Translated using Weblate (German)
Currently translated at 100.0% (39 of 39 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/emails/de/
2021-02-22 18:53:03 +01:00
virusperfect
b0bd6973d1 translation from Weblate (German)
Currently translated at 100.0% (118 of 118 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/de/
2021-02-22 18:53:02 +01:00
Killianbe
d10eb6d6bf Translated using Weblate (French)
Currently translated at 100.0% (39 of 39 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/emails/fr/
2021-02-22 18:53:02 +01:00
Richard de Boer
0c5a332fa2 translation from Weblate (Dutch)
Currently translated at 100.0% (118 of 118 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/nl/
2021-02-22 18:53:02 +01:00
Killianbe
5a07e103c0 translation from Weblate (French)
Currently translated at 100.0% (118 of 118 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/fr/
2021-02-22 18:53:01 +01:00
Harvey Tindall
40fc5e9604 Fix email editor when plaintext setting enabled 2021-02-22 16:40:37 +00:00
Harvey Tindall
9799665951 fix tag versioning and dockerfile 2021-02-22 01:26:07 +00:00
Harvey Tindall
b3fa667db1 version with ldflags instead of script 2021-02-22 01:23:42 +00:00
Harvey Tindall
027cf19d0f delete missing route bind 2021-02-22 01:05:18 +00:00
Harvey Tindall
38119551d7 merge translation 2021-02-22 00:45:07 +00:00
Harvey Tindall
52d9cda61a Move email rendering to browser
the email preview no longer has a delay after each change. This also
avoids a race condition in which the email currently being edited could
be actually sent.
2021-02-22 00:43:36 +00:00
ClankJake
f40fb9d3f7 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (39 of 39 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/emails/pt_BR/
2021-02-21 16:55:47 +01:00
ClankJake
9536ceaaa4 translation from Weblate (Portuguese (Brazil))
Currently translated at 100.0% (110 of 110 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/pt_BR/
2021-02-21 16:55:47 +01:00
ClankJake
72beee1322 translation from Weblate (Portuguese (Brazil))
Currently translated at 100.0% (27 of 27 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/form/pt_BR/
2021-02-21 16:55:47 +01:00
Richard de Boer
0ec822988d Translated using Weblate (Dutch)
Currently translated at 100.0% (39 of 39 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/emails/nl/
2021-02-21 16:55:47 +01:00
Harvey Tindall
d1b1b90de3 Add email list accessible by edit button in settings 2021-02-21 15:51:42 +00:00
Harvey Tindall
058cac2e7b implement email editor w/ live(?) preview
not accessible in the ui currently, but the object is available as
window.ee for testing.
2021-02-20 22:49:59 +00:00
Harvey Tindall
6ffdd4dad7 fix mistype in german email 2021-02-20 01:31:34 +00:00
Harvey Tindall
98d59ba4e0 don't strip text on images 2021-02-20 01:20:43 +00:00
Harvey Tindall
938523c18b fix urls in custom email/announcements
Uses a nasty algorithm found in stripmd.go to change all occurrences
of '[linktext](link)' to just 'link' before passing to a decent markdown
stripper.
2021-02-20 01:03:11 +00:00
Harvey Tindall
cc4e12c405 finish backend of custom emails
biggest bodge i've ever done but it works i guess.
2021-02-20 00:22:40 +00:00
Harvey Tindall
eb406ef951 Implement email template generation
Variables are surrounded by {}, and initial (default) templates are
generated on demand from the plaintext version of emails. The custom
emails are intended to only be used if the user actually changes them,
as they lose the features of the default ones, such as tables.
2021-02-19 21:38:20 +00:00
Harvey Tindall
5c87d109a3 use descriptive variable names in email translations
in preparation for an email editor.
2021-02-19 17:50:50 +00:00
Harvey Tindall
3e020da66a merge translation 2021-02-19 16:12:27 +00:00
Harvey Tindall
78157f763f use different color library, wrap logger functions with it 2021-02-19 16:12:14 +00:00
Richard de Boer
bcc0eeeb2f Translated using Weblate (Dutch)
Currently translated at 100.0% (95 of 95 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/setup/nl/
2021-02-19 15:58:27 +01:00
Richard de Boer
76b859f5bf Translated using Weblate (Dutch)
Currently translated at 100.0% (32 of 32 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/emails/nl/
2021-02-19 15:58:27 +01:00
Richard de Boer
676cf619d5 translation from Weblate (Dutch)
Currently translated at 100.0% (27 of 27 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/form/nl/
2021-02-19 15:58:27 +01:00
Richard de Boer
ce45bf2136 translation from Weblate (Dutch)
Currently translated at 100.0% (110 of 110 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/nl/
2021-02-19 15:58:26 +01:00
Harvey Tindall
b25f786018 use bulk email sending on account deletion 2021-02-19 14:51:36 +00:00
Harvey Tindall
ca00796077 Merge pull request #61 from rigrig/main
use `apt-get` instead of `apt` in Dockerfile
2021-02-19 14:47:10 +00:00
Richard de Boer
a1bbf13d6a use apt-get instead of apt
Because `apt` is meant for humans, and complains when called in scripts.
(manpage: "While it tries not to break backward compatibility this is not guaranteed")
2021-02-19 15:26:11 +01:00
Harvey Tindall
76fa171575 cleanup logs and use structs in jf/emby api
Also means times are directly parsed when pulling data from jf/emby,
which was *painful* to get working (something broke the whole program and it
took me an hour to figure out it was this lol). Time parsing should be a
lot stabler too.
2021-02-19 00:47:01 +00:00
Killianbe
ce30537ebd translation from Weblate (French)
Currently translated at 100.0% (110 of 110 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.dev/projects/jfa-go/admin/fr/
2021-02-18 19:34:07 +01:00
Harvey Tindall
93b5b483cc add plaintext email option, use text/template
text/template is used on plaintext emails to avoid escaping of certain
characters.
2021-02-18 18:26:23 +00:00
Harvey Tindall
27ef931670 add possible dark mode fix for Outlook 2021-02-18 17:47:15 +00:00
Harvey Tindall
fb727e75ec substitute jellyfin strings on emails, hopefully fix dark mode 2021-02-18 16:09:58 +00:00
Harvey Tindall
fa433c88a8 add announcement emails
After selecting users in the accounts tab, you can press 'Announce',
then write a subject and message (with markdown), and an email will be
sent to each selected user.
2021-02-18 14:58:53 +00:00
Harvey Tindall
adbb5b9d38 Fix filepath separator and external files on windows
For some reason, '/' is used instead of '\' on windows when loading
lang. FSJoin will now use whatever already exists in the path.
app.GetPath now creates a DirFS from the containing directory instead of
app.systemFS, which fixes loading on windows.
2021-02-18 12:58:30 +00:00
Harvey Tindall
cdc837e781 trim '/' from path when using systemFS
should fix #58.
2021-02-17 22:02:26 +00:00
Harvey Tindall
a92baa5d18 update urls 2021-02-17 20:52:49 +00:00
Harvey Tindall
e913f25a47 update buildrone url 2021-02-17 20:31:52 +00:00
Harvey Tindall
9eb803388e add it-it email back 2021-02-17 16:54:09 +00:00
Harvey Tindall
eb81515f46 fix ordering of steps in dockerfile 2021-02-17 16:53:15 +00:00
Harvey Tindall
52461c0356 add it-it email back 2021-02-17 16:36:39 +00:00
Harvey Tindall
6b3800abf6 remove branch trigger 2021-02-17 16:34:04 +00:00
Harvey Tindall
09fc81d7f4 fix tag recognition by drone 2021-02-17 16:26:14 +00:00
Harvey Tindall
82034a2586 use python3 in makefile for embed 2021-02-17 16:11:01 +00:00
Harvey Tindall
5e001bed60 temporarily modify lang for release
Fixed name on Indonesian and removed Italian emails.
2021-02-17 16:04:25 +00:00
Harvey Tindall
5d7972db56 rename embed/noembed to internal-files/external-files 2021-02-17 14:41:44 +00:00
Harvey Tindall
403ad58274 move all scripts to scripts/ 2021-02-17 14:32:03 +00:00
Harvey Tindall
a1a233e74f fix sed path in Dockerfile 2021-02-17 11:33:41 +00:00
Harvey Tindall
8dd72c95ab switch image for drone builds 2021-02-17 11:19:51 +00:00
Harvey Tindall
f794322392 Merge branch 'go1.16'
merge go1.16 changes

This includes embedded files for releases (no extra 'data' directory!)
and support for a custom language file directory, allowing one to
customize the text accross the app.
2021-02-17 11:15:21 +00:00
Harvey Tindall
afd52d1d37 Use go cross-compilation in docker build
significantly faster builds now. Every pre-compilation step (typescript,
css, etc.) happens natively, then GOARCH=xxx make compile is also run
natively for each architecture. The output it then copied into each
container.
2021-02-16 16:08:53 +00:00
Harvey Tindall
ba7370171a lowercase lang, go mod tidy 2021-02-16 14:31:31 +00:00
frankwalter1301
deb364a8bd Translated using Weblate (Italian)
Currently translated at 71.8% (23 of 32 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/emails/it/
2021-02-16 15:16:58 +01:00
frankwalter1301
a3cf498e15 translation from Weblate (Italian)
Currently translated at 100.0% (27 of 27 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/form/it/
2021-02-16 15:16:58 +01:00
mezzovide
3b356d2d8c Translated using Weblate (Indonesian)
Currently translated at 100.0% (95 of 95 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/setup/id/
2021-02-16 15:16:58 +01:00
Etienne dP
20e17b576a translation from Weblate (French)
Currently translated at 100.0% (103 of 103 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/admin/fr/
2021-02-16 15:16:58 +01:00
frankwalter1301
8e680ff576 Added translation using Weblate (Italian) 2021-02-16 15:16:58 +01:00
frankwalter1301
29d26aeb15 add translation from Weblate (Italian) 2021-02-16 15:16:58 +01:00
Harvey Tindall
33b7876826 build from tag on stable 2021-02-13 22:03:35 +00:00
Harvey Tindall
0fc4b5eb22 switch to buildx with qemu for builds 2021-02-13 21:59:33 +00:00
Harvey Tindall
e672f9f14c lowercase lang names 2021-02-13 20:51:35 +00:00
Harvey Tindall
4d2e509950 merge language changes 2021-02-13 20:50:27 +00:00
Harvey Tindall
a80e5c2aa9 purge manifest and recreate per build 2021-02-13 20:49:56 +00:00
Marketos Damigos
cd375208ba Translated using Weblate (Greek)
Currently translated at 100.0% (95 of 95 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/setup/el/
2021-02-13 17:57:39 +01:00
Marketos Damigos
316f482bf5 Translated using Weblate (Greek)
Currently translated at 100.0% (32 of 32 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/emails/el/
2021-02-13 17:57:39 +01:00
Marketos Damigos
0f78390282 translation from Weblate (Greek)
Currently translated at 100.0% (103 of 103 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/admin/el/
2021-02-13 17:57:39 +01:00
Marketos Damigos
0b909fc02d Translated using Weblate (Greek)
Currently translated at 100.0% (9 of 9 strings)

Translation: jfa-go/Common Strings
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/common-strings/el/
2021-02-13 17:57:39 +01:00
mezzovide
d4c6561abd Translated using Weblate (Indonesian)
Currently translated at 100.0% (32 of 32 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/emails/id/
2021-02-13 17:57:39 +01:00
Marketos Damigos
1f5e6537a5 translation from Weblate (Greek)
Currently translated at 100.0% (27 of 27 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/form/el/
2021-02-13 17:57:39 +01:00
mezzovide
97f2ae34ca Translated using Weblate (Indonesian)
Currently translated at 1.0% (1 of 95 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/setup/id/
2021-02-13 17:57:39 +01:00
mezzovide
d193afbeca translation from Weblate (Indonesian)
Currently translated at 100.0% (27 of 27 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/form/id/
2021-02-13 17:57:39 +01:00
mezzovide
abea430b6b Translated using Weblate (Indonesian)
Currently translated at 100.0% (9 of 9 strings)

Translation: jfa-go/Common Strings
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/common-strings/id/
2021-02-13 17:57:39 +01:00
mezzovide
00cec2b157 translation from Weblate (Indonesian)
Currently translated at 100.0% (103 of 103 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/admin/id/
2021-02-13 17:57:39 +01:00
Marketos Damigos
41ff0be839 Translated using Weblate (Greek)
Currently translated at 1.0% (1 of 95 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/setup/el/
2021-02-13 17:57:39 +01:00
mezzovide
25330533bd add translation from Weblate (Indonesian) 2021-02-13 17:57:39 +01:00
mezzovide
4afd1bd4b5 Added translation using Weblate (Indonesian) 2021-02-13 17:57:39 +01:00
mezzovide
cf185efdfc add translation from Weblate (Indonesian) 2021-02-13 17:57:39 +01:00
mezzovide
4ec9756f58 Added translation using Weblate (Indonesian) 2021-02-13 17:57:39 +01:00
mezzovide
cda7db5718 Added translation using Weblate (Indonesian) 2021-02-13 17:57:39 +01:00
Marketos Damigos
3b37fb5692 Added translation using Weblate (Greek) 2021-02-13 17:57:39 +01:00
Marketos Damigos
40c83803de Added translation using Weblate (Greek) 2021-02-13 17:57:39 +01:00
Marketos Damigos
a9811c164e Added translation using Weblate (Greek) 2021-02-13 17:57:39 +01:00
Marketos Damigos
8f000876b3 add translation from Weblate (Greek) 2021-02-13 17:57:39 +01:00
Marketos Damigos
0af393236f add translation from Weblate (Greek) 2021-02-13 17:57:39 +01:00
hrfee
3153c65f5a Translated using Weblate (English)
Currently translated at 100.0% (95 of 95 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/setup/en/
2021-02-13 17:57:39 +01:00
virusperfect
6ce825bd41 translation from Weblate (German)
Currently translated at 100.0% (103 of 103 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/admin/de/
2021-02-13 17:57:38 +01:00
Harvey Tindall
060f0efc16 pull containers before manifest, run on different host 2021-02-13 14:05:04 +00:00
Harvey Tindall
c3fb00a307 wrong go version container 2021-02-12 15:37:19 +00:00
Harvey Tindall
988829a6db dont build docker on go1.16 branch 2021-02-12 15:22:21 +00:00
Harvey Tindall
76935a300a dont build docker on go1.16 branch 2021-02-12 15:21:58 +00:00
Harvey Tindall
a6a7710a79 use filepath.Join wrapper for different embed and os path styles
If using internal, "/" is used as a separator always, and with external,
filepath.Join is used.
2021-02-12 14:59:35 +00:00
Harvey Tindall
873afb47cd strip debug symbols in makefile 2021-02-12 14:59:35 +00:00
Harvey Tindall
ea99966057 refactor, move route loading to router.go 2021-02-12 14:59:16 +00:00
Harvey Tindall
aaed272bf2 use embed.fs wrapper on data 2021-02-12 14:35:16 +00:00
Harvey Tindall
e6775cd2d1 use embed.fs wrapper for langFS so lang/ is not needed in paths
[files]lang_files is now the path to the lang directory, not path to a
directory containing it.
2021-02-12 14:35:16 +00:00
Harvey Tindall
98a9e20cc0 Fix docker build, add GOBINARY flag for make
GOBINARY defaults to "go", but if you want to build on a normal system,
you'll likely set it to go1.16rc1 with "make all GOBINARY=go1.16rc1".
2021-02-12 14:35:13 +00:00
Harvey Tindall
ee37588959 drone image 2021-02-12 14:32:57 +00:00
Harvey Tindall
cb12c6f441 update goreleaser 2021-02-12 14:32:57 +00:00
Harvey Tindall
72cf3e2240 add external/internal data options
"make all" will build with internal data, whereas "make debug"/"make
all-external" will make an external "data/" directory.
2021-02-12 14:32:48 +00:00
Harvey Tindall
815bdc35ac fully self-contained
paths are pretty janky, but it works. Also, [files]/lang_files now must
be the path to a directory CONTAINING a "lang/" directory. I'll work
around this at a later date.
2021-02-12 14:28:09 +00:00
Harvey Tindall
0330540f87 Use fs for language, add lang_files option
The local app translations are loaded, and then if [files]/lang_files
is provided (a directory containing custom translations), any found
inside it are loaded over top. This makes customizing much easier.
2021-02-12 14:28:09 +00:00
Harvey Tindall
fefe2d82a4 rebase 12/02, use go1.16rc1 in make, remove ioutil, start switching to io/fs for file i/o
ioutil's contents are now in io and os.
Eventually jfa-go's files will be embedded in the binary with go1.16's
new embed feature. Using io/fs will provide abstraction for accessing
these files, and allow for both embedded and non-embedded versions.
Also, internal paths to things like email templates, etc. will be
prefixed with "jfa-go:" to indicate to use the app's own Filesystem
instead of reading the file normally. This also allows for custom files
to continue to be used as they are currently.
2021-02-12 14:27:01 +00:00
Harvey Tindall
1af8d1f77d fix url in account creation success page 2021-02-12 13:38:34 +00:00
Harvey Tindall
4c653fea36 fix url base on invite and broken getLanguages 2021-02-12 12:52:08 +00:00
Harvey Tindall
2ee0ed55f6 forgot key agh 2021-02-12 00:35:20 +00:00
Harvey Tindall
94981f4891 dont use drone manifest plugin 2021-02-11 23:52:05 +00:00
Harvey Tindall
f72def0399 serve on / and URL base for easy proxying 2021-02-11 23:06:51 +00:00
Harvey Tindall
81fb0fc69f fix triggers aarch64 = arm64 2021-02-11 22:25:00 +00:00
Harvey Tindall
c3af0f4380 remove tag event from unstable build 2021-02-11 21:48:57 +00:00
Harvey Tindall
3a9e4950d4 run docker amd64 builds on drone, attempt multiarch 2021-02-11 21:18:32 +00:00
Harvey Tindall
06dada297b up command_timeout for slow rpi builds 2021-02-11 18:47:24 +00:00
Harvey Tindall
2b55a1873c fix css, oops 2021-02-11 18:28:25 +00:00
Harvey Tindall
c2e68bdc77 add GOESBUILD option for platform without esbuild on npm 2021-02-11 18:21:21 +00:00
Harvey Tindall
e1c3b312ff split armhf and arm64, add stable build 2021-02-11 16:24:32 +00:00
Harvey Tindall
e235ed9fda fix key again 2021-02-11 16:14:39 +00:00
Harvey Tindall
5cda12dd3b separate into pipelines, add armhf 2021-02-11 16:11:07 +00:00
Harvey Tindall
a9d48083fd fix keyfile 2021-02-11 15:48:13 +00:00
Harvey Tindall
e28c50401e use key path 2021-02-11 15:37:02 +00:00
Harvey Tindall
4a3b015a40 start adding automated arm builds 2021-02-11 15:29:33 +00:00
Harvey Tindall
1a6727312c dont override header on email confirmation fail 2021-02-11 14:04:15 +00:00
Harvey Tindall
91d3d2596e fix broken invite links 2021-02-11 13:49:06 +00:00
Harvey Tindall
192c9a4764 account for lack of trailing slash in url 2021-02-09 20:45:35 +00:00
Harvey Tindall
173c38563e remove embed, oops 2021-02-08 15:43:20 +00:00
Harvey Tindall
d061721f56 explicitly set js mimetype 2021-02-08 15:25:02 +00:00
Harvey Tindall
218882b7c6 remove debug console.log 2021-02-08 11:50:58 +00:00
Harvey Tindall
fed3ee4c4f Create FUNDING.yml 2021-02-08 01:01:48 +00:00
Harvey Tindall
8eed4b0127 merge language again 2021-02-05 18:25:56 +00:00
Harvey Tindall
c09ffb49e7 switch emails to normal text when not editing
fixes padding on small screens.
2021-02-05 18:24:27 +00:00
ClankJake
f331f4eb92 translation from Weblate (Portuguese (Brazil))
Currently translated at 100.0% (103 of 103 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/admin/pt_BR/
2021-02-05 15:55:38 +01:00
Richard de Boer
629b669c64 translation from Weblate (Dutch)
Currently translated at 100.0% (103 of 103 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/admin/nl/
2021-02-05 15:55:38 +01:00
Cornichon420
2dab900748 translation from Weblate (French)
Currently translated at 100.0% (103 of 103 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/admin/fr/
2021-02-05 15:55:38 +01:00
hrfee
f864097f2e translation from Weblate (English)
Currently translated at 100.0% (103 of 103 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/admin/en/
2021-02-05 15:55:38 +01:00
Harvey Tindall
2c8be42bbc fix invite links with URL base 2021-02-05 13:33:34 +00:00
Harvey Tindall
6691ae27f4 fix navigation with URL base set 2021-02-05 13:31:56 +00:00
Harvey Tindall
23fecb16b2 merge language changes 2021-02-05 13:11:00 +00:00
Harvey Tindall
b037b08152 respect URL Base in http preloads and inline html links 2021-02-05 13:10:47 +00:00
ClankJake
46fe3a7f5d Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (32 of 32 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/emails/pt_BR/
2021-02-03 10:04:41 +01:00
virusperfect
61bd62403f Translated using Weblate (German)
Currently translated at 100.0% (95 of 95 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/setup/de/
2021-02-03 10:04:41 +01:00
ClankJake
5893d4b855 translation from Weblate (Portuguese (Brazil))
Currently translated at 100.0% (27 of 27 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/form/pt_BR/
2021-02-03 10:04:41 +01:00
virusperfect
8016e6f211 Translated using Weblate (German)
Currently translated at 100.0% (32 of 32 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/emails/de/
2021-02-03 10:04:41 +01:00
virusperfect
a5560b04bd translation from Weblate (German)
Currently translated at 100.0% (27 of 27 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/form/de/
2021-02-03 10:04:41 +01:00
Richard de Boer
b9e171b1fd Translated using Weblate (Dutch)
Currently translated at 100.0% (32 of 32 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/emails/nl/
2021-02-03 10:04:41 +01:00
Cornichon420
a633425baa Translated using Weblate (French)
Currently translated at 100.0% (32 of 32 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/emails/fr/
2021-02-03 10:04:41 +01:00
Richard de Boer
e29e89c618 translation from Weblate (Dutch)
Currently translated at 100.0% (27 of 27 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/form/nl/
2021-02-03 10:04:41 +01:00
Cornichon420
62c986161c translation from Weblate (French)
Currently translated at 100.0% (27 of 27 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/form/fr/
2021-02-03 10:04:41 +01:00
ClankJake
6279c73402 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (32 of 32 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/emails/pt_BR/
2021-02-03 10:04:41 +01:00
ClankJake
22e103837f translation from Weblate (Portuguese (Brazil))
Currently translated at 100.0% (101 of 101 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/admin/pt_BR/
2021-02-03 10:04:41 +01:00
ClankJake
feba6e7bae Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (95 of 95 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/setup/pt_BR/
2021-02-03 10:04:41 +01:00
Harvey Tindall
95a6b48c3e add go1.16 branch do drone builds
This branch has fully self-contained binaries, so I thought it'd be a
good idea to build it alongside.
2021-02-01 18:43:30 +00:00
Harvey Tindall
90c6cee780 add restart button 2021-01-31 19:01:20 +00:00
Harvey Tindall
456ef556b1 add inter-section dependency for settings
Currently used to hide all email sections when [email]/method is blank
(disabled).
2021-01-31 18:50:04 +00:00
Harvey Tindall
ce98b2eb5a add backwards navigation 2021-01-31 17:32:03 +00:00
Harvey Tindall
ee026714d4 Add optional email confirmation
If enabled, a confirmation email will be sent before the user can create
their account.
2021-01-30 19:19:12 +00:00
Harvey Tindall
736c39840f fix default jellyfin path for setup in dockerfile 2021-01-29 17:13:15 +00:00
Harvey Tindall
e755bc6b61 fix language names 2021-01-29 13:49:58 +00:00
Richard de Boer
7ec9f2435c translation from Weblate (Dutch)
Currently translated at 100.0% (101 of 101 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/admin/nl/
2021-01-29 14:42:20 +01:00
Cornichon420
443d6fee52 Translated using Weblate (French)
Currently translated at 100.0% (32 of 32 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/emails/fr/
2021-01-29 14:42:20 +01:00
Cornichon420
b023616033 translation from Weblate (French)
Currently translated at 100.0% (25 of 25 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/form/fr/
2021-01-29 14:42:20 +01:00
Cornichon420
f182b88c58 Translated using Weblate (French)
Currently translated at 100.0% (95 of 95 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/setup/fr/
2021-01-29 14:42:20 +01:00
Richard de Boer
93daadae4b translation from Weblate (Dutch)
Currently translated at 100.0% (25 of 25 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/form/nl/
2021-01-29 14:42:20 +01:00
virusperfect
fd1ec5d3fb Translated using Weblate (German)
Currently translated at 100.0% (95 of 95 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/setup/de/
2021-01-29 14:42:20 +01:00
virusperfect
b9a8a27807 translation from Weblate (German)
Currently translated at 100.0% (101 of 101 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/admin/de/
2021-01-29 14:42:20 +01:00
Cornichon420
27a36898a3 translation from Weblate (French)
Currently translated at 100.0% (101 of 101 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/admin/fr/
2021-01-29 14:42:20 +01:00
Richard de Boer
d8948c037b Translated using Weblate (Dutch)
Currently translated at 100.0% (32 of 32 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/emails/nl/
2021-01-29 14:42:20 +01:00
virusperfect
83f2749eab Translated using Weblate (German)
Currently translated at 100.0% (32 of 32 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/emails/de/
2021-01-29 14:42:20 +01:00
virusperfect
290435b5ba translation from Weblate (German)
Currently translated at 100.0% (25 of 25 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/form/de/
2021-01-29 14:42:20 +01:00
Cornichon420
d09125c63c Translated using Weblate (French)
Currently translated at 100.0% (8 of 8 strings)

Translation: jfa-go/Common Strings
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/common-strings/fr/
2021-01-29 14:42:20 +01:00
Cornichon420
f0aa64373b Added translation using Weblate (French) 2021-01-29 14:42:20 +01:00
DesertCookie
2272883d5a translation from Weblate (German)
Currently translated at 100.0% (25 of 25 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/form/de/
2021-01-29 14:42:20 +01:00
Richard de Boer
2d0f6d89aa Translated using Weblate (Dutch)
Currently translated at 100.0% (95 of 95 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/setup/nl/
2021-01-29 14:42:20 +01:00
hrfee
4cd1571c05 Translated using Weblate (Dutch)
Currently translated at 100.0% (95 of 95 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/setup/nl/
2021-01-29 14:42:20 +01:00
ClankJake
55be62bc3e Translated using Weblate (Portuguese (Brazil))
Currently translated at 98.9% (94 of 95 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/setup/pt_BR/
2021-01-29 14:42:20 +01:00
ClankJake
da82f1c146 translation from Weblate (Portuguese (Brazil))
Currently translated at 100.0% (25 of 25 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/form/pt_BR/
2021-01-29 14:42:20 +01:00
DesertCookie
67f53d4112 Translated using Weblate (German)
Currently translated at 100.0% (32 of 32 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/emails/de/
2021-01-29 14:42:20 +01:00
ClankJake
88356281fb translation from Weblate (Portuguese (Brazil))
Currently translated at 97.0% (98 of 101 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/admin/pt_BR/
2021-01-29 14:42:20 +01:00
ClankJake
05198ea764 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (32 of 32 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/emails/pt_BR/
2021-01-29 14:42:20 +01:00
ClankJake
fe33d97d87 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (8 of 8 strings)

Translation: jfa-go/Common Strings
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/common-strings/pt_BR/
2021-01-29 14:42:20 +01:00
DesertCookie
2c60dee48a translation from Weblate (German)
Currently translated at 100.0% (101 of 101 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/admin/de/
2021-01-29 14:42:20 +01:00
Richard de Boer
8af9f9944a Translated using Weblate (Dutch)
Currently translated at 72.6% (69 of 95 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/setup/nl/
2021-01-29 14:42:20 +01:00
DesertCookie
4e968d2338 Translated using Weblate (German)
Currently translated at 97.8% (93 of 95 strings)

Translation: jfa-go/Setup
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/setup/de/
2021-01-29 14:42:20 +01:00
Richard de Boer
7ba88977a4 Added translation using Weblate (Dutch) 2021-01-29 14:42:20 +01:00
hrfee
0c5f6a68f9 Added translation using Weblate (Portuguese (Brazil)) 2021-01-29 14:42:20 +01:00
ClankJake
bbd539278c add translation from Weblate (Portuguese (Brazil)) 2021-01-29 14:42:20 +01:00
DesertCookie
be9d9ac6ff Added translation using Weblate (German) 2021-01-29 14:42:20 +01:00
ClankJake
e8b37a5df8 Added translation using Weblate (Portuguese (Brazil)) 2021-01-29 14:42:20 +01:00
ClankJake
d10d347e2b Added translation using Weblate (Portuguese (Brazil)) 2021-01-29 14:42:20 +01:00
ClankJake
68689d74a0 add translation from Weblate (Portuguese (Brazil)) 2021-01-29 14:42:20 +01:00
Harvey Tindall
4fc9bdb35b element already existed, oops 2021-01-29 01:32:44 +00:00
Harvey Tindall
c0a05be44e add strftime notice on setup
string was already in translations, just forgot to include it.
2021-01-29 01:29:54 +00:00
Harvey Tindall
482c9d5719 update license date 2021-01-29 01:20:05 +00:00
virusperfect
f063298bf7 Translated using Weblate (German)
Currently translated at 100.0% (32 of 32 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/emails/de/
2021-01-27 23:11:35 +01:00
virusperfect
bb1e454850 translation from Weblate (German)
Currently translated at 100.0% (108 of 108 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/admin/de/
2021-01-27 23:11:35 +01:00
Cornichon420
11770d90f1 translation from Weblate (French)
Currently translated at 100.0% (108 of 108 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/admin/fr/
2021-01-27 23:11:35 +01:00
hrfee
8a415140b6 Translated using Weblate (English)
Currently translated at 100.0% (32 of 32 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/emails/en/
2021-01-27 23:11:35 +01:00
Harvey Tindall
3dd83bffbf Merge branch 'new-setup'
Merge new setup wizard

This is much more up-to-date than the previous setup page, with a new
design and previously missing/new settings. Currently only available in
english (hopefully that changes soon).

also fixes conflict in _post.
2021-01-27 22:06:44 +00:00
Harvey Tindall
79987ffa22 add refresh button that uses url base if given 2021-01-27 21:51:01 +00:00
Harvey Tindall
764639bbba add header template 2021-01-27 21:38:35 +00:00
Harvey Tindall
eb67116ee6 replace og setup 2021-01-27 21:37:43 +00:00
Harvey Tindall
7baea9101e Add general settings, ombi
host, port, theme, tls are included in general. Page theme changes with
setting. Fixed checkbox support messages. Split some cards into columns.
2021-01-27 21:35:41 +00:00
Harvey Tindall
167fae9892 add jellyfin connection test, submission
fully functional now, but still need to add some sections (ombi mainly).
2021-01-27 12:55:39 +00:00
Harvey Tindall
c7f5aa2e2b split into pages, hide email pages when disabled, add history navigation 2021-01-27 00:51:19 +00:00
Harvey Tindall
8c871bc5fa Add ts to link setting dependance
Also make store each setting as classes in a settings object, to make it
easier to serialize on submitting. Also, added
"substitute_jellyfin_strings", "no_username" and welcome_email.
2021-01-26 22:57:29 +00:00
Harvey Tindall
1f6bbc75ff remove junk files 2021-01-26 00:39:35 +00:00
Harvey Tindall
23ae18d732 compile setup.ts in Makefile/Goreleaser
surprised there hasn't been issues for this, the setup page would've
been broken for a while.
2021-01-26 00:37:32 +00:00
Harvey Tindall
bf1e6230dc split some strings into common file; use lang file to setup page 2021-01-25 21:26:54 +00:00
Harvey Tindall
8af1c13d7e Display error messages on form
two new strings need translating in lang/form.
2021-01-25 18:01:18 +00:00
Harvey Tindall
061945218a fix extra whitespace after pin code
for #39
2021-01-25 17:18:35 +00:00
Harvey Tindall
687edf2b0b Initial setup page content
Rewritten with a17t. Content right now is just a copy of the original
setup.html, but settings for new features will be added later.Currently
all cards are shown, only the current one will show in future.
2021-01-24 23:05:04 +00:00
Cornichon420
1bf1e994fe Translated using Weblate (French)
Currently translated at 100.0% (32 of 32 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/emails/fr/
2021-01-24 18:27:28 +01:00
Cornichon420
7f91a27e4f translation from Weblate (French)
Currently translated at 100.0% (23 of 23 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/form/fr/
2021-01-24 18:27:28 +01:00
Cornichon420
f66510c74b translation from Weblate (French)
Currently translated at 100.0% (108 of 108 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/admin/fr/
2021-01-24 18:27:28 +01:00
Weblate
e5de8b20ff merge branch 'origin/main' into Weblate. 2021-01-24 16:57:46 +01:00
Harvey Tindall
dd96d71280 Add optional label for invites
Requested in #38.
2021-01-24 15:55:45 +00:00
Richard de Boer
a687b2c438 translation from Weblate (Dutch)
Currently translated at 100.0% (105 of 105 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/admin/nl/
2021-01-24 16:22:39 +01:00
Harvey Tindall
ea262ca60b add optional welcome email for new users
When enabled, an email with the server URL and username will be sent to
created users. Requested in #38.
2021-01-24 15:19:58 +00:00
Harvey Tindall
406fef6595 bundle typescript 2021-01-23 19:08:27 +00:00
Harvey Tindall
f7d8feac5d bundle css with esbuild 2021-01-23 18:53:14 +00:00
Harvey Tindall
cd2ea2e579 reload email after lang is loaded
fixes #37.
2021-01-21 18:57:32 +00:00
Harvey Tindall
b66654787c make whole invite clickable to expand 2021-01-21 17:59:16 +00:00
Harvey Tindall
882a3467db fix language settings loading 2021-01-21 14:16:03 +00:00
Harvey Tindall
27ac0bf43e merge german translation 2021-01-21 11:49:20 +00:00
Harvey Tindall
4485622354 remove some comments 2021-01-21 10:56:58 +00:00
virusperfect
91b2b44768 Translated using Weblate (German)
Currently translated at 100.0% (27 of 27 strings)

Translation: jfa-go/Emails
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/emails/de/
2021-01-21 11:52:46 +01:00
virusperfect
8c276fa0a7 translation from Weblate (German)
Currently translated at 100.0% (23 of 23 strings)

Translation: jfa-go/Account Creation Form
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/form/de/
2021-01-21 11:52:46 +01:00
virusperfect
78b0e22091 translation from Weblate (German)
Currently translated at 100.0% (105 of 105 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/admin/de/
2021-01-21 11:52:46 +01:00
hrfee
96abbdf9a8 Added translation using Weblate (German) 2021-01-20 09:03:49 +01:00
hrfee
7c61392ff4 add translation from Weblate (German) 2021-01-20 09:03:18 +01:00
hrfee
901abfb3e5 add translation from Weblate (German) 2021-01-20 09:02:35 +01:00
hrfee
2eea836d9f translation from Weblate (French)
Currently translated at 100.0% (105 of 105 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/admin/fr/
2021-01-19 01:31:18 +01:00
hrfee
9a08a6603a Deleted translation using Weblate (English (United Kingdom)) 2021-01-19 01:31:18 +01:00
hrfee
887126f5dd Translated using Weblate (English (United Kingdom))
Currently translated at 1.9% (2 of 105 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.hrfee.pw/projects/jfa-go/admin/en_GB/
2021-01-19 01:31:18 +01:00
hrfee
fad6a04a5f Added translation using Weblate (English (United Kingdom)) 2021-01-19 01:31:18 +01:00
Harvey Tindall
e834445b0b Restructure language loading to support incomplete translations
On startup, files are scanned and any missing values are replaced with
the english version.
2021-01-19 00:29:29 +00:00
Harvey Tindall
1aadd12006 move validationStrings out of strings in lang/form 2021-01-18 22:06:50 +00:00
Harvey Tindall
26a1f30d32 Fix initial language setting value
For some reason it was set as en-US, not en-us.
2021-01-18 00:14:12 +00:00
Harvey Tindall
e0a17c6a74 mention new weblate instance 2021-01-17 20:02:02 +00:00
Harvey Tindall
7ce1b5001c merge nl-nl with invite url fix 2021-01-17 12:38:50 +00:00
Harvey Tindall
72a7759ca5 Fix invite link when non-default language selected 2021-01-17 12:36:16 +00:00
Richard de Boer
bf46c9f906 add dutch translation of emails 2021-01-17 12:32:50 +00:00
Richard de Boer
14bb85f301 add dutch translation of admin pages 2021-01-17 12:32:50 +00:00
180 changed files with 18755 additions and 4300 deletions

View File

@@ -10,18 +10,70 @@ steps:
- git fetch --tags
- name: release
image: golang:latest
volumes:
- name: ssh_key
path: /id_rsa
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 gcc libgtk-3-dev libappindicator3-dev gcc-mingw-w64-x86-64 -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 'sftp -P 2022 -i /id_rsa -o StrictHostKeyChecking=no root@161.97.102.153:/repo/incoming <<< $"put dist/*.deb"'
- bash -c 'ssh -i /id_rsa root@161.97.102.153 -p 2022 "repo-process-deb trusty"'
- bash -c 'python3 ../upload.py https://builds.hrfee.pw hrfee jfa-go --tag internal=true'
volumes:
- name: ssh_key
host:
path: /root/.ssh/id_rsa_packaging
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
@@ -30,21 +82,66 @@ type: docker
steps:
- name: build
image: golang:latest
volumes:
- name: ssh_key
path: /id_rsa
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 gcc libgtk-3-dev libappindicator3-dev gcc-mingw-w64-x86-64 -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 'sftp -P 2022 -i /id_rsa -o StrictHostKeyChecking=no root@161.97.102.153:/repo/incoming <<< $"put dist/*.deb"'
- bash -c 'ssh -i /id_rsa root@161.97.102.153 -p 2022 "repo-process-deb trusty"'
- bash -c 'python3 upload.py https://builds.hrfee.pw hrfee jfa-go --upload ./dist/*.zip ./dist/*.rpm ./dist/*.apk --tag internal-git=true'
environment:
BUILDRONE_KEY:
from_secret: BUILDRONE_KEY
volumes:
- name: ssh_key
host:
path: /root/.ssh/id_rsa_packaging
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
@@ -52,6 +149,10 @@ trigger:
exclude:
- pull_request
volumes:
- name: ssh_key
host:
path: /root/.ssh/docker-build
---
name: jfa-go-pr
kind: pipeline
@@ -61,13 +162,13 @@ 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 gcc libgtk-3-dev libappindicator3-dev gcc-mingw-w64-x86-64 -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
trigger:
event:

3
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,3 @@
github: hrfee
ko_fi: hrfee
custom: https://www.buymeacoffee.com/hrfee

3
.gitignore vendored
View File

@@ -12,3 +12,6 @@ config-payload.json
server.key
server.pem
server.crt
instructions-debian.txt
cl.md
./telegram/

View File

@@ -10,48 +10,152 @@ 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: ./
- id: notray
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
- darwin
goarch:
- amd64
- arm
- arm64
- amd64
- id: windows-tray
dir: ./
env:
- CGO_ENABLED=1
- CC=x86_64-w64-mingw32-gcc
- CXX=x86_64-w64-mingw32-g++
flags:
- -tags=tray
ldflags:
- -s -w -X main.version={{.Env.JFA_GO_VERSION}} -X main.commit={{.ShortCommit}} -X main.updater=binary -H=windowsgui
goos:
- windows
goarch:
- amd64
- id: linux-tray
dir: ./
env:
- CGO_ENABLED=1
flags:
- -tags=tray
ldflags:
- -s -w -X main.version={{.Env.JFA_GO_VERSION}} -X main.commit={{.ShortCommit}} -X main.updater=binary
goos:
- linux
goarch:
- amd64
archives:
- replacements:
darwin: Darwin
- id: windows-tray
builds:
- windows-tray
format: zip
name_template: "{{ .ProjectName }}_{{ .Version }}_TrayIcon_{{ .Os }}_{{ .Arch }}"
replacements:
darwin: macOS
linux: Linux
windows: Windows
amd64: x86_64
- id: linux-tray
builds:
- linux-tray
format: zip
name_template: "{{ .ProjectName }}_{{ .Version }}_TrayIcon_{{ .Os }}_{{ .Arch }}"
replacements:
darwin: macOS
linux: Linux
windows: Windows
amd64: x86_64
- id: notray
builds:
- notray
format: zip
name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
replacements:
darwin: macOS
linux: Linux
windows: Windows
amd64: x86_64
files:
- data/*
- data/**/*
- data/**/**/*
checksum:
name_template: 'checksums.txt'
snapshot:
name_template: "git-{{.ShortCommit}}"
name_template: "0.0.0-{{.ShortCommit}}"
changelog:
sort: asc
filters:
exclude:
- '^docs:'
- '^test:'
nfpms:
- id: notray
file_name_template: '{{ .ProjectName }}{{ if .IsSnapshot }}-git{{ end }}_{{ .Arch }}_{{ if .IsSnapshot }}{{ .ShortCommit }}{{ else }}v{{ .Version }}{{ end }}'
package_name: jfa-go
homepage: https://github.com/hrfee/jfa-go
description: A web app for managing users on Jellyfin
maintainer: Harvey Tindall <hrfee@hrfee.dev>
license: MIT
vendor: hrfee.dev
version_metadata: git
builds:
- notray
contents:
- src: ./LICENSE
dst: /usr/share/licenses/jfa-go
formats:
- apk
- deb
- rpm
- id: tray
file_name_template: '{{ .ProjectName }}{{ if .IsSnapshot }}-git{{ end }}_TrayIcon_{{ .Arch }}_{{ if .IsSnapshot }}{{ .ShortCommit }}{{ else }}v{{ .Version }}{{ end }}'
package_name: jfa-go-tray
homepage: https://github.com/hrfee/jfa-go
description: A web app for managing users on Jellyfin
maintainer: Harvey Tindall <hrfee@hrfee.dev>
license: MIT
vendor: hrfee.dev
version_metadata: git
builds:
- linux-tray
contents:
- src: ./LICENSE
dst: /usr/share/licenses/jfa-go
formats:
- apk
- deb
- rpm
overrides:
deb:
conflicts:
- jfa-go
replaces:
- jfa-go
dependencies:
- libappindicator3-1
rpm:
dependencies:
- libappindicator-gtk3
apk:
dependencies:
- libappindicator

View File

@@ -1,12 +1,20 @@
#### Translation
Currently the admin page, account creation form and emails can be translated. Strings are defined in `lang/<admin/form/email>/<country-code>.json` (country code as in `en-us`, `fr-fr`, e.g). You can see the existing ones [here](https://github.com/hrfee/jfa-go/tree/main/lang).
Make sure to define `name` in the `meta` section, and you can optionally add an `author` value there as well. If you can, make a pull request with your new file. If not, email me or create an issue.
#### 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.
If you need to test your changes:
* `make debug` will build everything, and include sourcemaps for typescript. This should be the first thing you run.
* `make compile` compiles go into `build/jfa-go`.
* `make ts-debug` will compile typescript w/ sourcemaps into `build/data/web/js`.
* `make copy` will copy css, html, language and static files into `build/data`.
Code in Go should ideally use `PascalCase` for exported values, and `camelCase` for non-exported, JSON for transferring data should use `snake_case`, and Typescript should use `camelCase`. Forgive me for my many inconsistencies in this, and feel free to fix them if you want.
Functions in Go that need to access `*appContext` should be generally be receivers, except when the behaviour could be seen as somewhat independent from it (`email.go` is the best example, its behaviour is broadly independent from the main app except from a couple config values).
#### 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.

View File

@@ -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" ]

View File

@@ -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

149
Makefile
View File

@@ -1,65 +1,144 @@
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
TRAY ?= off
ifeq ($(INTERNAL)$(TRAY), offon)
TAGS := $(TAGS) tray
else ifeq ($(INTERNAL)$(TRAY), onon)
TAGS := -tags tray
endif
OS := $(shell go env GOOS)
ifeq ($(TRAY)$(OS), onwindows)
LDFLAGS := $(LDFLAGS) -H=windowsgui
endif
DEBUG ?= off
ifeq ($(DEBUG), on)
SOURCEMAP := --sourcemap
TYPECHECK := tsc -noEmit --project ts/tsconfig.json
# jank
COPYTS := rm -r $(DATA)/web/js/ts; cp -r ts $(DATA)/web/js
else
LDFLAGS := -s -w $(LDFLAGS)
SOURCEMAP :=
COPYTS :=
TYPECHECK :=
endif
RACE ?= off
ifeq ($(RACE), on)
RACEDETECTOR := -race
else
RACEDETECTOR :=
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
$(GOBINARY) build $(RACEDETECTOR) -ldflags="$(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

113
README.md
View File

@@ -1,26 +1,35 @@
![jfa-go](images/banner.svg)
[![Build Status](https://drone.hrfee.pw/api/badges/hrfee/jfa-go/status.svg?ref=refs/heads/main)](https://drone.hrfee.pw/hrfee/jfa-go)
[![Build Status](https://drone.hrfee.dev/api/badges/hrfee/jfa-go/status.svg?ref=refs/heads/main)](https://drone.hrfee.dev/hrfee/jfa-go)
[![Docker Hub](https://img.shields.io/docker/pulls/hrfee/jfa-go?label=docker)](https://hub.docker.com/r/hrfee/jfa-go)
[![Translation status](https://weblate.hrfee.pw/widgets/jfa-go/-/svg-badge.svg)](https://weblate.hrfee.pw/engage/jfa-go/)
##### Downloads:
##### [docker](#docker) | [debian/ubuntu](#debian) | [arch (aur)](#aur) | [other platforms](#other-platforms)
---
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.
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.
a rewrite of [jellyfin-accounts](https://github.com/hrfee/jellyfin-accounts) (original naming for both, ik
😂).
#### 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.
* 🧑 Invite based account creation: Send invites to your friends or family, and let them choose their own username and password without relying on you.
* Send invites via a link and/or email
* 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 & Discord Integration: Verify users via a Telegram or Discord bot, 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
@@ -30,32 +39,66 @@ I chose to rewrite the python [jellyfin-accounts](https://github.com/hrfee/jelly
</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/).
**Note**: `TrayIcon` builds include a tray icon to start/stop/restart, and an option to automatically start when you log-in to your computer. For Linux users, these builds depend on the `libappindicator3-1`/`libappindicator-gtk3`/`libappindicator` package for Debian/Ubuntu, Fedora, and Alpine respectively.
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:
```
##### [Docker](https://hub.docker.com/r/hrfee/jfa-go)
```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
```
##### [Debian/Ubuntu](https://apt.hrfee.dev)
```sh
sudo apt-get update && sudo apt-get install curl apt-transport-https gnupg
curl https://apt.hrfee.dev/hrfee.pubkey.gpg | sudo apt-key add -
# For stable releases
echo "deb https://apt.hrfee.dev trusty main" | sudo tee /etc/apt/sources.list.d/hrfee.list
# ------
# For unstable releases
echo "deb https://apt.hrfee.dev trusty-unstable main" | sudo tee /etc/apt/sources.list.d/hrfee.list
# ------
sudo apt-get update
# For servers
sudo apt-get install jfa-go
# ------
# For desktops/servers with GUI (has dependencies)
sudo apt-get install jfa-go-tray
# ------
```
##### Arch
Available on the AUR as:
* [jfa-go](https://aur.archlinux.org/packages/jfa-go/) (stable)
* [jfa-go-bin](https://aur.archlinux.org/packages/jfa-go) (pre-compiled, stable)
* [jfa-go-git](https://aur.archlinux.org/packages/jfa-go-git/) (nightly)
##### Other platforms
Download precompiled binaries from:
* [The releases section](https://github.com/hrfee/jfa-go/releases) (stable)
* [Buildrone](https://builds.hrfee.dev/view/hrfee/jfa-go) (nightly)
unzip the `jfa-go`/`jfa-go.exe` 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.
@@ -64,24 +107,38 @@ 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
alternate path to config file. (default "~/.config/jfa-go/config.ini")
-data string
alternate path to data directory. (default "~/.config/jfa-go")
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.
-config, -c string
alternate path to config file. (default "/home/hrfee/.config/jfa-go/config.ini")
-data, -d string
alternate path to data directory. (default "/home/hrfee/.config/jfa-go")
-debug
Enables debug logging and exposes pprof.
Enables debug logging.
-help, -h
prints this message.
-host string
alternate address to host web ui on.
-port int
-port, -p int
alternate port to host web ui on.
-pprof
Exposes pprof profiler on /debug/pprof.
-swagger
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,
@@ -92,3 +149,7 @@ If you're switching from jellyfin-accounts, copy your existing `~/.jf-accounts`
#### Contributing
See [CONTRIBUTING.md](https://github.com/hrfee/jfa-go/blob/main/CONTRIBUTING.md).
##### Translation
[![Translation status](https://weblate.hrfee.pw/widgets/jfa-go/-/multi-auto.svg)](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.

View File

@@ -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>

2039
api.go

File diff suppressed because it is too large Load Diff

154
args.go Normal file
View 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)
}

View File

@@ -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

69
autostart.go Normal file
View File

@@ -0,0 +1,69 @@
// +build tray
package main
import (
"log"
"os"
"path/filepath"
"github.com/emersion/go-autostart"
"github.com/getlantern/systray"
)
type Autostart struct {
as *autostart.App
enabled bool
menuitem *systray.MenuItem
clicked chan bool
}
func NewAutostart(name, displayname, trayName, trayTooltip string) *Autostart {
a := &Autostart{
as: &autostart.App{
Name: name,
DisplayName: displayname,
},
enabled: true,
clicked: make(chan bool),
}
a.menuitem = systray.AddMenuItemCheckbox(trayName, trayTooltip, a.as.IsEnabled())
command := os.Args
command[0], _ = filepath.Abs(command[0])
// Make sure to replace any relative paths with absolute ones
pathArgs := []string{"-d", "-data", "-c", "-config"}
for i := 1; i < len(command); i++ {
isPath := false
for _, p := range pathArgs {
if command[i-1] == p {
isPath = true
break
}
}
if isPath {
command[i], _ = filepath.Abs(command[i])
}
}
a.as.Exec = command
return a
}
func (a *Autostart) HandleCheck() {
for range a.menuitem.ClickedCh {
if !a.menuitem.Checked() {
if err := a.as.Enable(); err != nil {
log.Printf("Failed to enable autostart on login: %v", err)
} else {
a.menuitem.Check()
log.Printf("Enabled autostart")
}
} else {
if err := a.as.Disable(); err != nil {
log.Printf("Failed to disable autostart on login: %v", err)
} else {
a.menuitem.Uncheck()
log.Printf("Disabled autostart")
}
}
}
}

View File

@@ -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.

190
config.go
View File

@@ -2,6 +2,8 @@ package main
import (
"fmt"
"io/fs"
"os"
"path/filepath"
"strconv"
"strings"
@@ -9,31 +11,24 @@ 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
var discordEnabled = false
var matrixEnabled = 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,43 +37,100 @@ 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", "invites", "emails", "user_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", "discord_users", "matrix_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.MustSetValue("matrix", "topic", "Jellyfin notifications")
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)
discordEnabled = app.config.Section("discord").Key("enabled").MustBool(false)
matrixEnabled = app.config.Section("matrix").Key("enabled").MustBool(false)
if !messagesEnabled {
emailEnabled = false
telegramEnabled = false
discordEnabled = false
matrixEnabled = false
} else if app.config.Section("email").Key("method").MustString("") == "" {
emailEnabled = false
} else {
emailEnabled = true
}
if !emailEnabled && !telegramEnabled && !discordEnabled && !matrixEnabled {
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("")
@@ -92,8 +144,60 @@ func (app *appContext) loadConfig() error {
}
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()
}
func (app *appContext) migrateEmailStorage() error {
var emails map[string]interface{}
err := loadJSON(app.storage.emails_path, &emails)
if err != nil {
return err
}
newEmails := map[string]EmailAddress{}
for jfID, addr := range emails {
newEmails[jfID] = EmailAddress{
Addr: addr.(string),
Contact: true,
}
}
err = storeJSON(app.storage.emails_path+".bak", emails)
if err != nil {
return err
}
err = storeJSON(app.storage.emails_path, newEmails)
if err != nil {
return err
}
app.info.Println("Migrated to new email format. A backup has also been made.")
return nil
}

View File

@@ -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.

File diff suppressed because it is too large Load Diff

View File

@@ -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"`
}

View File

@@ -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;
@@ -30,15 +30,41 @@
}
}
@media screen and (max-width: 750px) {
@media screen and (max-width: 1000px) {
:root {
font-size: 0.9rem;
}
.table-responsive table {
min-width: 660px;
min-width: 800px;
}
}
.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,14 @@
text-align: right;
}
.ac {
text-align: center;
}
.w-100 {
width: 100%;
}
.inline-block {
display: inline-block;
}
@@ -133,6 +175,21 @@
margin: 0.5rem;
}
p.sm,
span.sm:not(.heading) {
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 +205,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 +258,7 @@ sup.\~critical, .text-critical {
max-width: 40%;
min-width: 10rem;
display: flex;
justify-content: center;
justify-content: start;
align-items: center;
}
@@ -252,10 +310,18 @@ sup.\~critical, .text-critical {
width: 100%;
}
.flex-auto {
flex: auto;
}
.center {
justify-content: center;
}
.middle {
align-items: center;
}
.no-lp {
padding-left: 0px;
}
@@ -362,6 +428,7 @@ p.top {
.table-responsive {
overflow-x: auto;
font-size: 0.9rem;
}
#notification-box {
@@ -375,3 +442,82 @@ p.top {
padding-bottom: 0.5rem;
margin-bottom: -0.5rem;
}
.dropdown-display.lg {
white-space: nowrap;
}
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;
}
td.img-circle {
width: 32px;
height: 32px;
}
span.img-circle.lg {
width: 64px;
height: 64px;
}
span.shield.img-circle {
padding: 0.2rem;
}
img.img-circle {
border-radius: 50%;
vertical-align: middle;
}
.table td.sm {
padding-top: 0.1rem;
padding-bottom: 0.1rem;
}
.table-inline {
display: flex !important;
align-items: center;
}

View File

@@ -85,3 +85,7 @@
.dark-only {
display: initial;
}
.dark-theme select option {
background: #202020;
}

View File

@@ -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

410
discord.go Normal file
View File

@@ -0,0 +1,410 @@
package main
import (
"fmt"
"strings"
dg "github.com/bwmarrin/discordgo"
)
type DiscordDaemon struct {
Stopped bool
ShutdownChannel chan string
bot *dg.Session
username string
tokens []string
verifiedTokens map[string]DiscordUser // Map of tokens to discord users.
channelID, channelName, inviteChannelID, inviteChannelName string
guildID string
serverChannelName, serverName string
users map[string]DiscordUser // Map of user IDs to users. Added to on first interaction, and loaded from app.storage.discord on start.
app *appContext
}
func newDiscordDaemon(app *appContext) (*DiscordDaemon, error) {
token := app.config.Section("discord").Key("token").String()
if token == "" {
return nil, fmt.Errorf("token was blank")
}
bot, err := dg.New("Bot " + token)
if err != nil {
return nil, err
}
dd := &DiscordDaemon{
Stopped: false,
ShutdownChannel: make(chan string),
bot: bot,
tokens: []string{},
verifiedTokens: map[string]DiscordUser{},
users: map[string]DiscordUser{},
app: app,
}
for _, user := range app.storage.discord {
dd.users[user.ID] = user
}
return dd, nil
}
// NewAuthToken generates an 8-character pin in the form "A1-2B-CD".
func (d *DiscordDaemon) NewAuthToken() string {
pin := genAuthToken()
d.tokens = append(d.tokens, pin)
return pin
}
func (d *DiscordDaemon) NewUnknownUser(channelID, userID, discrim, username string) DiscordUser {
user := DiscordUser{
ChannelID: channelID,
ID: userID,
Username: username,
Discriminator: discrim,
}
return user
}
func (d *DiscordDaemon) MustGetUser(channelID, userID, discrim, username string) DiscordUser {
if user, ok := d.users[userID]; ok {
return user
}
return d.NewUnknownUser(channelID, userID, discrim, username)
}
func (d *DiscordDaemon) run() {
d.bot.AddHandler(d.messageHandler)
d.bot.Identify.Intents = dg.IntentsGuildMessages | dg.IntentsDirectMessages | dg.IntentsGuildMembers | dg.IntentsGuildInvites
if err := d.bot.Open(); err != nil {
d.app.err.Printf("Discord: Failed to start daemon: %v", err)
return
}
// Wait for everything to populate, it's slow sometimes.
for d.bot.State == nil {
continue
}
for d.bot.State.User == nil {
continue
}
d.username = d.bot.State.User.Username
for d.bot.State.Guilds == nil {
continue
}
// Choose the last guild (server), for now we don't really support multiple anyway
d.guildID = d.bot.State.Guilds[len(d.bot.State.Guilds)-1].ID
guild, err := d.bot.Guild(d.guildID)
if err != nil {
d.app.err.Printf("Discord: Failed to get guild: %v", err)
}
d.serverChannelName = guild.Name
d.serverName = guild.Name
if channel := d.app.config.Section("discord").Key("channel").String(); channel != "" {
d.channelName = channel
d.serverChannelName += "/" + channel
}
if d.app.config.Section("discord").Key("provide_invite").MustBool(false) {
if invChannel := d.app.config.Section("discord").Key("invite_channel").String(); invChannel != "" {
d.inviteChannelName = invChannel
}
}
defer d.bot.Close()
<-d.ShutdownChannel
d.ShutdownChannel <- "Down"
return
}
// NewTempInvite creates an invite link, and returns the invite URL, as well as the URL for the server icon.
func (d *DiscordDaemon) NewTempInvite(ageSeconds, maxUses int) (inviteURL, iconURL string) {
var inv *dg.Invite
var err error
if d.inviteChannelName == "" {
d.app.err.Println("Discord: Cannot create invite without channel specified in settings.")
return
}
if d.inviteChannelID == "" {
channels, err := d.bot.GuildChannels(d.guildID)
if err != nil {
d.app.err.Printf("Discord: Couldn't get channel list: %v", err)
return
}
found := false
for _, channel := range channels {
// channel, err := d.bot.Channel(ch.ID)
// if err != nil {
// d.app.err.Printf("Discord: Couldn't get channel: %v", err)
// return
// }
if channel.Name == d.inviteChannelName {
d.inviteChannelID = channel.ID
found = true
break
}
}
if !found {
d.app.err.Printf("Discord: Couldn't find invite channel \"%s\"", d.inviteChannelName)
return
}
}
// channel, err := d.bot.Channel(d.inviteChannelID)
// if err != nil {
// d.app.err.Printf("Discord: Couldn't get invite channel: %v", err)
// return
// }
inv, err = d.bot.ChannelInviteCreate(d.inviteChannelID, dg.Invite{
// Guild: d.bot.State.Guilds[len(d.bot.State.Guilds)-1],
// Channel: channel,
// Inviter: d.bot.State.User,
MaxAge: ageSeconds,
MaxUses: maxUses,
Temporary: false,
})
if err != nil {
d.app.err.Printf("Discord: Failed to create invite: %v", err)
return
}
inviteURL = "https://discord.gg/" + inv.Code
guild, err := d.bot.Guild(d.guildID)
if err != nil {
d.app.err.Printf("Discord: Failed to get guild: %v", err)
return
}
iconURL = guild.IconURL()
return
}
// Returns the user(s) roughly corresponding to the username (if they are in the guild).
// if no discriminator (#xxxx) is given in the username and there are multiple corresponding users, a list of all matching users is returned.
func (d *DiscordDaemon) GetUsers(username string) []*dg.Member {
members, err := d.bot.GuildMembers(
d.guildID,
"",
1000,
)
if err != nil {
d.app.err.Printf("Discord: Failed to get members: %v", err)
return nil
}
hasDiscriminator := strings.Contains(username, "#")
var users []*dg.Member
for _, member := range members {
if hasDiscriminator {
if member.User.Username+"#"+member.User.Discriminator == username {
return []*dg.Member{member}
}
}
if strings.Contains(member.User.Username, username) {
users = append(users, member)
}
}
return users
}
func (d *DiscordDaemon) NewUser(ID string) (user DiscordUser, ok bool) {
u, err := d.bot.User(ID)
if err != nil {
d.app.err.Printf("Discord: Failed to get user: %v", err)
return
}
user.ID = ID
user.Username = u.Username
user.Contact = true
user.Discriminator = u.Discriminator
channel, err := d.bot.UserChannelCreate(ID)
if err != nil {
d.app.err.Printf("Discord: Failed to create DM channel: %v", err)
return
}
user.ChannelID = channel.ID
ok = true
return
}
func (d *DiscordDaemon) Shutdown() {
d.Stopped = true
d.ShutdownChannel <- "Down"
<-d.ShutdownChannel
close(d.ShutdownChannel)
}
func (d *DiscordDaemon) messageHandler(s *dg.Session, m *dg.MessageCreate) {
if m.GuildID != "" && d.channelName != "" {
if d.channelID == "" {
channel, err := s.Channel(m.ChannelID)
if err != nil {
d.app.err.Printf("Discord: Couldn't get channel, will monitor all: %v", err)
d.channelName = ""
}
if channel.Name == d.channelName {
d.channelID = channel.ID
}
}
if d.channelID != m.ChannelID {
d.app.debug.Printf("Discord: Ignoring message as not in specified channel")
return
}
}
if m.Author.ID == s.State.User.ID {
return
}
sects := strings.Split(m.Content, " ")
if len(sects) == 0 {
return
}
lang := d.app.storage.lang.chosenTelegramLang
if user, ok := d.users[m.Author.ID]; ok {
if _, ok := d.app.storage.lang.Telegram[user.Lang]; ok {
lang = user.Lang
}
}
switch msg := sects[0]; msg {
case d.app.config.Section("discord").Key("start_command").MustString("!start"):
d.commandStart(s, m, lang)
case "!lang":
d.commandLang(s, m, sects, lang)
default:
d.commandPIN(s, m, sects, lang)
}
}
func (d *DiscordDaemon) commandStart(s *dg.Session, m *dg.MessageCreate, lang string) {
channel, err := s.UserChannelCreate(m.Author.ID)
if err != nil {
d.app.err.Printf("Discord: Failed to create private channel with \"%s\": %v", m.Author.Username, err)
return
}
user := d.MustGetUser(channel.ID, m.Author.ID, m.Author.Discriminator, m.Author.Username)
d.users[m.Author.ID] = user
content := d.app.storage.lang.Telegram[lang].Strings.get("startMessage") + "\n"
content += d.app.storage.lang.Telegram[lang].Strings.template("languageMessage", tmpl{"command": "!lang"})
_, err = s.ChannelMessageSend(channel.ID, content)
if err != nil {
d.app.err.Printf("Discord: Failed to send message to \"%s\": %v", m.Author.Username, err)
return
}
}
func (d *DiscordDaemon) commandLang(s *dg.Session, m *dg.MessageCreate, sects []string, lang string) {
if len(sects) == 1 {
list := "!lang <lang>\n"
for code := range d.app.storage.lang.Telegram {
list += fmt.Sprintf("%s: %s\n", code, d.app.storage.lang.Telegram[code].Meta.Name)
}
_, err := s.ChannelMessageSendReply(
m.ChannelID,
list,
m.Reference(),
)
if err != nil {
d.app.err.Printf("Discord: Failed to send message to \"%s\": %v", m.Author.Username, err)
}
return
}
if _, ok := d.app.storage.lang.Telegram[sects[1]]; ok {
var user DiscordUser
for jfID, user := range d.app.storage.discord {
if user.ID == m.Author.ID {
user.Lang = sects[1]
d.app.storage.discord[jfID] = user
if err := d.app.storage.storeDiscordUsers(); err != nil {
d.app.err.Printf("Failed to store Discord users: %v", err)
}
break
}
}
d.users[m.Author.ID] = user
}
}
func (d *DiscordDaemon) commandPIN(s *dg.Session, m *dg.MessageCreate, sects []string, lang string) {
if _, ok := d.users[m.Author.ID]; ok {
channel, err := s.Channel(m.ChannelID)
if err != nil {
d.app.err.Printf("Discord: Failed to get channel: %v", err)
return
}
if channel.Type != dg.ChannelTypeDM {
d.app.debug.Println("Discord: Ignoring message as not a DM")
return
}
} else {
d.app.debug.Println("Discord: Ignoring message as user was not found")
return
}
tokenIndex := -1
for i, token := range d.tokens {
if sects[0] == token {
tokenIndex = i
break
}
}
if tokenIndex == -1 {
_, err := s.ChannelMessageSend(
m.ChannelID,
d.app.storage.lang.Telegram[lang].Strings.get("invalidPIN"),
)
if err != nil {
d.app.err.Printf("Discord: Failed to send message to \"%s\": %v", m.Author.Username, err)
}
return
}
_, err := s.ChannelMessageSend(
m.ChannelID,
d.app.storage.lang.Telegram[lang].Strings.get("pinSuccess"),
)
if err != nil {
d.app.err.Printf("Discord: Failed to send message to \"%s\": %v", m.Author.Username, err)
}
d.verifiedTokens[sects[0]] = d.users[m.Author.ID]
d.tokens[len(d.tokens)-1], d.tokens[tokenIndex] = d.tokens[tokenIndex], d.tokens[len(d.tokens)-1]
d.tokens = d.tokens[:len(d.tokens)-1]
}
func (d *DiscordDaemon) SendDM(message *Message, userID ...string) error {
channels := make([]string, len(userID))
for i, id := range userID {
channel, err := d.bot.UserChannelCreate(id)
if err != nil {
return err
}
channels[i] = channel.ID
}
return d.Send(message, channels...)
}
func (d *DiscordDaemon) Send(message *Message, channelID ...string) error {
msg := ""
var embeds []*dg.MessageEmbed
if message.Markdown != "" {
msg, embeds = StripAltText(message.Markdown, true)
} else {
msg = message.Text
}
for _, id := range channelID {
var err error
if len(embeds) != 0 {
_, err = d.bot.ChannelMessageSendComplex(
id,
&dg.MessageSend{
Content: msg,
Embed: embeds[0],
},
)
if err != nil {
return err
}
for i := 1; i < len(embeds); i++ {
_, err := d.bot.ChannelMessageSendEmbed(id, embeds[i])
if err != nil {
return err
}
}
} else {
_, err := d.bot.ChannelMessageSend(
id,
msg,
)
if err != nil {
return err
}
}
}
return nil
}

904
email.go

File diff suppressed because it is too large Load Diff

37
external.go Normal file
View 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"))
}

49
go.mod
View File

@@ -1,54 +1,57 @@
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/mediabrowser => ./mediabrowser
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/bwmarrin/discordgo v0.23.2 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/emersion/go-autostart v0.0.0-20210130080809-00ed301c8e9a // indirect
github.com/fatih/color v1.10.0
github.com/fsnotify/fsnotify v1.4.9
github.com/getlantern/systray v1.1.0 // indirect
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-20210105184019-fdc97b4e86cc
github.com/hrfee/jfa-go/docs v0.0.0-20201112212552-b6f3cd7c1f71
github.com/hrfee/jfa-go/mediabrowser 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/mailgun/mailgun-go/v4 v4.5.1
github.com/mailru/easyjson v0.7.7 // indirect
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // 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-20210525063256-abc453219eb5 // indirect
golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea // indirect
golang.org/x/tools v0.1.1 // indirect
google.golang.org/protobuf v1.25.0 // indirect
gopkg.in/ini.v1 v1.62.0
)

327
go.sum
View File

@@ -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,58 @@ 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/bwmarrin/discordgo v0.23.2 h1:BzrtTktixGHIu9Tt7dEE6diysEF9HWnXeHuoJEt2fH4=
github.com/bwmarrin/discordgo v0.23.2/go.mod h1:c1WtWUGN6nREDmzIpyTp/iD3VYt4Fpx+bVyfBG7JE+M=
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/emersion/go-autostart v0.0.0-20210130080809-00ed301c8e9a h1:M88ob4TyDnEqNuL3PgsE/p3bDujfspnulR+0dQWNYZs=
github.com/emersion/go-autostart v0.0.0-20210130080809-00ed301c8e9a/go.mod h1:buzQsO8HHkZX2Q45fdfGH1xejPjuDQaXH8btcYMFzPM=
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/getlantern/context v0.0.0-20190109183933-c447772a6520 h1:NRUJuo3v3WGC/g5YiyF790gut6oQr5f3FBI88Wv0dx4=
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520/go.mod h1:L+mq6/vvYHKjCX2oez0CgEAJmbq1fbb/oNJIWQkBybY=
github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7 h1:6uJ+sZ/e03gkbqZ0kUG6mfKoqDb4XMAzMIwlajq19So=
github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7/go.mod h1:l+xpFBrCtDLpK9qNjxs+cHU6+BAdlBaxHqikB6Lku3A=
github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7 h1:guBYzEaLz0Vfc/jv0czrr2z7qyzTOGC9hiQ0VC+hKjk=
github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7/go.mod h1:zx/1xUUeYPy3Pcmet8OSXLbF47l+3y6hIPpyLWoR9oc=
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 h1:micT5vkcr9tOVk1FiH8SWKID8ultN44Z+yzd2y/Vyb0=
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7/go.mod h1:dD3CgOrwlzca8ed61CsZouQS5h5jIzkK9ZWrTcf0s+o=
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 h1:XYzSdCbkzOC0FDNrgJqGRo8PCMFOBFL9py72DRs7bmc=
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55/go.mod h1:6mmzY2kW1TOOrVy+r41Za2MxXM+hhqTtY3oBKd2AgFA=
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f h1:wrYrQttPS8FHIRSlsrcuKazukx/xqO/PpLZzZXsF+EA=
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA=
github.com/getlantern/systray v1.1.0 h1:U0wCEqseLi2ok1fE6b88gJklzriavPJixZysZPkZd/Y=
github.com/getlantern/systray v1.1.0/go.mod h1:AecygODWIsBquJCJFop8MEQcJbWFfw/1yWbVabNgpCM=
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 +70,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 +78,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 +110,20 @@ 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-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
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,177 +131,165 @@ 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/hrfee/jfa-go/jfapi v0.0.0-20210109010027-4aae65518089 h1:WRk+JAywI8V4u+PBQpdvXBX73yCZxgnLwyIiX7xL+Xc=
github.com/hrfee/jfa-go/jfapi v0.0.0-20210109010027-4aae65518089/go.mod h1:Al1Rd1JGtpS+3KnK8t7+J0CZVDbT86QJrXHR6kZijds=
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/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
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/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16 h1:ZtO5uywdd5dLDCud4r0r55eP4j9FuUNpl60Gmntcop4=
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s=
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/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
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/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA=
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
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=
github.com/yuin/goldmark v1.3.5 h1:dPmz1Snjq0kmkz159iL7S6WzdahUTHnHB5M56WFVifs=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
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-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
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/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/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=
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -307,110 +301,95 @@ 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/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210510120150-4163338589ed h1:p9UgmWI9wKpfYmgaV/IZKGdXc5qEK45tDwwwDyjS26I=
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210521195947-fe42d452be8f h1:Si4U+UcgJzya9kpiEUJKQvjr512OLli+gL4poHrz93U=
golang.org/x/net v0.0.0-20210521195947-fe42d452be8f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5 h1:wjuX4b5yYQnEQHzd+CBcrcC6OVR2J1CN6mUy0oSxIPo=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
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/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/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-20200515095857-1151b9dac4a9/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/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 h1:hZR0X1kPW+nwyJ9xRxqZk1vx5RUObAPBdKVvXPDUH/E=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210521203332-0cec03c779c1 h1:lCnv+lfrU9FRPGf8NeRuWAAPjNnema5WtBinMgs1fD8=
golang.org/x/sys v0.0.0-20210521203332-0cec03c779c1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea h1:+WiDlPBBaO+h9vPNZi8uJ3k4BkKQB7Iow3aqwHVA5hI=
golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/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/tools v0.1.1 h1:wGiQel/hW0NnEkJUk8lbzkX2gFJU6PFxf1v5OlCfuOs=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
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=
@@ -418,36 +397,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=

View File

@@ -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>

View File

@@ -1,14 +1,18 @@
<!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.discordEnabled = {{ .discord_enabled }};
window.matrixEnabled = {{ .matrix_enabled }};
window.ombiEnabled = {{ .ombiEnabled }};
window.usernameEnabled = {{ .username }};
window.langFile = JSON.parse({{ .language }});
window.language = "{{ .langName }}";
</script>
{{ template "header.html" . }}
<title>Admin - jfa-go</title>
@@ -39,12 +43,26 @@
</div>
<div id="modal-about" class="modal">
<div class="modal-content content card">
<span class="heading">{{ .strings.aboutProgram }} <span class="modal-close">&times;</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">&times;</span></span>
<p><i class="icon ri-github-fill"></i><a href="https://github.com/hrfee/jfa-go">jfa-go</a></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">
@@ -93,6 +111,119 @@
</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">&times;</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">&times;</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">&times;</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">&times;</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">{{ .strings.settingsRestartRequired }} <span class="modal-close">&times;</span></span>
@@ -165,6 +296,64 @@
</label>
</form>
</div>
<div id="modal-update" class="modal">
<div class="modal-content wide card">
<span class="heading">{{ .strings.updates }} <span class="modal-close">&times;</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>
&#64;<span id="telegram-username">
</a>
<span class="button ~info !normal full-width center mt-1" id="telegram-waiting">{{ .strings.success }}</span>
</div>
</div>
{{ end }}
{{ if .discord_enabled }}
<div id="modal-discord" class="modal">
<div class="modal-content card">
<span class="heading mb-1"><span id="discord-header"></span><span class="modal-close">&times;</span></span>
<p class="content mb-1" id="discord-description"></p>
<div class="row">
<input type="search" class="col sm field ~neutral !normal input" id="discord-search" placeholder="user#1234">
</div>
<table class="table"><tbody id="discord-list"></tbody></table>
</div>
</div>
{{ end }}
<div id="modal-matrix" class="modal">
<form class="modal-content card" id="form-matrix" href="">
<span class="heading">{{ .strings.linkMatrix }}</span>
<p class="content">{{ .strings.linkMatrixDescription }}</p>
<input type="text" class="field input ~neutral !high mt-half mb-1" placeholder="{{ .strings.matrixHomeServer }}" id="matrix-homeserver">
<input type="text" class="field input ~neutral !high mt-half mb-1" placeholder="{{ .strings.username }}" id="matrix-user">
<input type="password" class="field input ~neutral !high mt-half mb-1" placeholder="{{ .strings.password }}" id="matrix-password">
<label>
<input type="submit" class="unfocused">
<span class="button ~urge !normal full-width center supra submit">{{ .strings.submit }}</span>
</label>
</form>
</div>
<div id="notification-box"></div>
<span class="dropdown" tabindex="0" id="lang-dropdown">
<span class="button ~urge dropdown-button">
@@ -172,7 +361,16 @@
<span class="ml-1 chev"></span>
</span>
<div class="dropdown-display">
<div class="card ~neutral !low" id="lang-list">
<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>
@@ -201,30 +399,109 @@
<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">{{ .strings.inviteDays }}</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">{{ .strings.inviteHours }}</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">{{ .strings.inviteMinutes }}</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">{{ .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>
@@ -238,7 +515,14 @@
<div id="create-send-to-container">
<label class="label supra">{{ .strings.inviteSendToEmail }}</label>
<div class="flex-expand mb-1 mt-half">
{{ if .discord_enabled }}
<input type="text" id="create-send-to" class="input ~neutral !normal mr-1" placeholder="example@example.com | user#1234">
<span id="create-send-to-search" class="button ~neutral !normal mr-1">
<i class="icon ri-search-2-line" title="{{ .strings.search }}"></i>
</span>
{{ else }}
<input type="email" id="create-send-to" class="input ~neutral !normal mr-1" placeholder="example@example.com">
{{ end }}
<label for="create-send-to-enabled" class="button ~neutral !normal">
<input type="checkbox" id="create-send-to-enabled" aria-label="Send to address enabled">
</label>
@@ -251,11 +535,19 @@
</div>
<div id="tab-accounts" class="unfocused">
<div class="card ~neutral !low accounts mb-1">
<span class="heading">{{ .strings.accounts }}</span>
<div class="fr">
<span class="button ~neutral !normal" id="accounts-add-user">{{ .quantityStrings.addUser.singular }}</span>
<span class="button ~urge !normal" id="accounts-modify-user">{{ .strings.modifySettings }}</span>
<span class="button ~critical !normal" id="accounts-delete-user">{{ .quantityStrings.deleteUser.singular }}</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">
@@ -264,6 +556,16 @@
<th><input type="checkbox" value="" id="accounts-select-all"></th>
<th>{{ .strings.username }}</th>
<th>{{ .strings.emailAddress }}</th>
{{ if .telegram_enabled }}
<th>Telegram</th>
{{ end }}
{{ if .matrix_enabled }}
<th>Matrix</th>
{{ end }}
{{ if .discord_enabled }}
<th>Discord</th>
{{ end }}
<th>{{ .strings.expiry }}</th>
<th>{{ .strings.lastActiveTime }}</th>
</tr>
</thead>
@@ -274,9 +576,18 @@
</div>
<div id="tab-settings" class="unfocused">
<div class="card ~neutral !low settings overflow">
<span class="heading">{{ .strings.settings }}</span>
<div class="fr">
<span class="button ~neutral !normal unfocused" id="settings-save">{{ .strings.settingsSave }}</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">
@@ -289,6 +600,6 @@
</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
View 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>

View File

@@ -1,10 +1,30 @@
{{ 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 }}";
window.discordEnabled = {{ .discordEnabled }};
window.discordRequired = {{ .discordRequired }};
window.discordPIN = "{{ .discordPIN }}";
window.discordInviteLink = {{ .discordInviteLink }};
window.discordServerName = "{{ .discordServerName }}";
window.matrixEnabled = {{ .matrixEnabled }};
window.matrixRequired = {{ .matrixRequired }};
window.matrixUserID = "{{ .matrixUser }}";
</script>
<script src="js/form.js" type="module"></script>
{{ end }}

View File

@@ -1,19 +1,71 @@
<!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>
<a class="button ~urge !normal full-width center supra submit" href="{{ .jfLink }}" id="create-success-button">{{ .lang.successContinueButton }}</a>
<a class="button ~urge !normal full-width center supra submit" href="{{ .jfLink }}" id="create-success-button">{{ .strings.successContinueButton }}</a>
</div>
</div>
<div id="notification-box"></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>
&#64;{{ .telegramUsername }}
</a>
<span class="button ~info !normal full-width center mt-1" id="telegram-waiting">{{ .strings.success }}</span>
</div>
</div>
{{ end }}
{{ if .discordEnabled }}
<div id="modal-discord" class="modal">
<div class="modal-content card">
<span class="heading mb-1">{{ .strings.linkDiscord }}</span>
<p class="content mb-1"> {{ .discordSendPINMessage }}</p>
<h1 class="ac">{{ .discordPIN }}</h1>
<a id="discord-invite"></a>
<span class="button ~info !normal full-width center mt-1" id="discord-waiting">{{ .strings.success }}</span>
</div>
</div>
{{ end }}
{{ if .matrixEnabled }}
<div id="modal-matrix" class="modal">
<div class="modal-content card">
<span class="heading mb-1">{{ .strings.linkMatrix }}</span>
<p class="content mb-1"> {{ .strings.matrixEnterUser }}</p>
<input type="text" class="input ~neutral !high" placeholder="@user:riot.im" id="matrix-userid">
<div class="subheading link-center mt-1">
<span class="shield ~info mr-1">
<span class="icon">
<i class="ri-chat-3-line"></i>
</span>
</span>
{{ .matrixUser }}
</div>
<span class="button ~info !normal full-width center mt-1" id="matrix-send">{{ .strings.submit }}</span>
</div>
</div>
{{ end }}
<span class="dropdown" tabindex="0" id="lang-dropdown">
<span class="button ~urge dropdown-button">
<i class="ri-global-line"></i>
@@ -24,37 +76,71 @@
</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>
{{ end }}
{{ if .discordEnabled }}
<span class="button ~info !normal full-width center mb-1" id="link-discord">{{ .strings.linkDiscord }}</span>
{{ end }}
{{ if .matrixEnabled }}
<span class="button ~info !normal full-width center mb-1" id="link-matrix">{{ .strings.linkMatrix }}</span>
{{ end }}
{{ if or (.telegramEnabled) (or .discordEnabled .matrixEnabled) }}
<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>
{{ if .telegramEnabled }}
<label class="row switch pb-1">
<input type="radio" name="contact-via" value="telegram" id="contact-via-telegram"><span>Contact through Telegram</span>
</label>
{{ end }}
{{ if .discordEnabled }}
<label class="row switch pb-1">
<input type="radio" name="contact-via" value="discord" id="contact-via-discord"><span>Contact through Discord</span>
</label>
{{ end }}
{{ if .matrixEnabled }}
<label class="row switch pb-1">
<input type="radio" name="contact-via" value="matrix" id="contact-via-matrix"><span>Contact through Matrix</span>
</label>
{{ end }}
</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 }}">
@@ -70,9 +156,6 @@
</div>
</div>
</div>
<script>
window.validationStrings = {{ .lang.validationStrings }};
</script>
{{ template "form-base" . }}
</body>
</html>

View File

@@ -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">

View File

@@ -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
View 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>

View File

@@ -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 &amp; 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>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 MiB

After

Width:  |  Height:  |  Size: 1.9 MiB

BIN
images/discord/1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

BIN
images/discord/2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
images/discord/3.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
images/discord/4.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

BIN
images/discord/5.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
images/discord/6.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

BIN
images/discord/7.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

BIN
images/discord/8.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 83 KiB

BIN
images/matrix/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 KiB

BIN
images/matrix/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

BIN
images/matrix/3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

BIN
images/matrix/4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
images/tg-settings.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
images/tg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

42
internal.go Normal file
View 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
View File

@@ -0,0 +1,8 @@
[Unit]
Description=An account management system for Jellyfin.
[Service]
ExecStart={executable}
[Install]
WantedBy=default.target

221
lang.go Normal file
View 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
}

192
lang/admin/de-de.json Normal file
View File

@@ -0,0 +1,192 @@
{
"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": "Benachrichtigung 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": "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",
"reEnable": "Wieder aktivieren",
"disable": "Deaktivieren",
"donate": "Spenden",
"conditionals": "Bedingungen",
"contactThrough": "Kontakt über:",
"sendPIN": "Bitte den Benutzer, die unten stehende PIN an den Bot zu senden.",
"inviteMonths": "Monate"
},
"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 Willkommensnachricht (ü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.",
"updateAppliedRefresh": "Update angewendet, bitte aktualisieren.",
"telegramVerified": "Telegram-Konto verifiziert."
},
"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."
},
"disabledUser": {
"plural": "Benutzer {n} Deaktiviert.",
"singular": "Benutzer {n} Deaktiviert."
},
"enabledUser": {
"singular": "Benutzer {n} Aktiviert.",
"plural": "Benutzer {n} Aktiviert."
},
"disableUsers": {
"singular": "Benutzer {n} deaktivieren",
"plural": "Deaktiviere {n} Benutzer"
},
"reEnableUsers": {
"singular": "Benutzer {n} wieder aktivieren",
"plural": "Benutzer {n} wieder aktivieren"
}
}
}

186
lang/admin/el-gr.json Normal file
View 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
View File

@@ -0,0 +1,5 @@
{
"meta": {
"name": "English (GB)"
}
}

View File

@@ -6,11 +6,12 @@
"invites": "Invites",
"accounts": "Accounts",
"settings": "Settings",
"theme": "Theme",
"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",
@@ -19,34 +20,60 @@
"create": "Create",
"apply": "Apply",
"delete": "Delete",
"submit": "Submit",
"add": "Add",
"select": "Select",
"name": "Name",
"date": "Date",
"username": "Username",
"password": "Password",
"emailAddress": "Email Address",
"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",
"success": "Success",
"error": "Error",
"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 email",
"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",
"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",
@@ -59,26 +86,34 @@
"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",
"copy": "Copy",
"inviteDateCreated": "Created",
"inviteRemainingUses": "Remaining uses",
"inviteNoInvites": "None",
"inviteExpiresInTime": "Expires in {n}",
"notifyEvent": "Notify on:",
"notifyInviteExpiry": "On expiry",
"notifyUserCreation": "On user creation"
"notifyUserCreation": "On user creation",
"sendPIN": "Ask the user to send the PIN below to the bot.",
"searchDiscordUser": "Start typing the Discord username to find the user.",
"findDiscordUser": "Find Discord user",
"linkMatrixDescription": "Enter the username and password of the user to use as a bot. Once submitted, the app will restart.",
"matrixHomeServer": "Home server address"
},
"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.",
"accountConnected": "Account connected.",
"errorConnection": "Couldn't connect to jfa-go.",
"error401Unauthorized": "Unauthorized. Try refreshing the page.",
"errorSettingsAppliedNoHomescreenLayout": "Settings were applied, but applying homescreen layout may have failed.",
@@ -86,6 +121,7 @@
"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.",
@@ -98,9 +134,14 @@
"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)"
"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",
@@ -110,6 +151,14 @@
"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"
@@ -122,9 +171,29 @@
"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."
}
}
}

188
lang/admin/es-es.json Normal file
View File

@@ -0,0 +1,188 @@
{
"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",
"donate": "Donar"
},
"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}."
}
}
}

View File

@@ -1,31 +1,27 @@
{
"meta": {
"name": "Francais (FR)",
"name": "Français (FR)",
"author": "https://github.com/Killianbe"
},
"strings": {
"invites": "Invite",
"invites": "Invitations",
"accounts": "Comptes",
"settings": "Reglages",
"theme": "Thème",
"settings": "Réglages",
"inviteMonths": "Mois",
"inviteDays": "Jours",
"inviteHours": "Heures",
"inviteMinutes": "Minutes",
"inviteNumberOfUses": "Nombre d'utilisateur",
"inviteNumberOfUses": "Nombre d'utilisateurs",
"warning": "Attention",
"inviteInfiniteUsesWarning": "les invitations infinies peuvent être utilisées abusivement",
"inviteSendToEmail": "Envoyer à",
"login": "S'identifier",
"logout": "Se déconecter",
"logout": "Se déconnecter",
"create": "Créer",
"apply": "Appliquer",
"delete": "Effacer",
"submit": "Soumettre",
"name": "Nom",
"date": "Date",
"username": "Nom d'utilisateur",
"password": "Mot de passe",
"emailAddress": "Addresse Email",
"lastActiveTime": "Dernière activité",
"from": "De",
"user": "Utilisateur",
@@ -34,45 +30,72 @@
"commitNoun": "Commettre",
"newUser": "Nouvel utilisateur",
"profile": "Profil",
"success": "Succès",
"error": "Erreur",
"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 ",
"sendDeleteNotificationEmail": "Envoyer un message 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. ",
"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 ",
"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. ",
"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, de nouveaux utilisateurs seront créés avec les paramètres. ",
"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!",
"inviteNoUsersCreated": "Aucun pour l'instant !",
"inviteUsersCreated": "Utilisateurs créer",
"inviteNoProfile": "Aucun profil",
"copy": "Copier",
"inviteDateCreated": "Créer",
"inviteRemainingUses": "Utilisations restantes",
"inviteNoInvites": "Aucune",
"inviteExpiresInTime": "Expires dans {n}",
"notifyEvent": "Notifier sur:",
"notifyEvent": "Notifier sur :",
"notifyInviteExpiry": "À l'expiration",
"notifyUserCreation": "à la création de l'utilisateur"
"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",
"userExpiryDescription": "Un laps de temps spécifié après chaque inscription, jfa-go supprimera / désactivera le compte. Vous pouvez modifier ce comportement dans les paramètres.",
"donate": "Faire un don",
"extendExpiry": "Prolonger l'expiration",
"contactThrough": "Contactez par :",
"sendPIN": "Demandez à l'utilisateur d'envoyer le code PIN ci-dessous au bot."
},
"notifications": {
"changedEmailAddress": "Adresse e-mail modifiée de {n}.",
@@ -85,13 +108,13 @@
"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",
"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",
"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.",
@@ -99,7 +122,19 @@
"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)"
"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 message 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.",
"errorApplyUpdate": "Échec de l'application de la mise à jour, essayez manuellement.",
"errorCheckUpdate": "Échec de la vérification de la mise à jour.",
"updateAvailable": "Une nouvelle mise à jour est disponible, vérifiez les paramètres.",
"noUpdatesAvailable": "Aucune nouvelle mise à jour disponible.",
"telegramVerified": "Compte Telegram vérifié.",
"updateAppliedRefresh": "Mise à jour appliquée, veuillez actualiser."
},
"quantityStrings": {
"modifySettingsFor": {
@@ -119,12 +154,40 @@
"plural": "Supprimer les utilisateurs"
},
"deletedUser": {
"singular": "Supprimer {n} utilisateur.",
"plural": "Supprimer {n} utilisateurs."
"singular": "Supprimer {n} utilisateur.",
"plural": "Supprimer {n} utilisateurs."
},
"appliedSettings": {
"singular": "Appliquer le paramètre {n} utilisteur.",
"plural": "Appliquer les paramètres {n} utilisteurs."
"singular": "Appliquer le paramètre {n} utilisteur.",
"plural": "Appliquer les paramètres {n} utilisteurs."
},
"announceTo": {
"singular": "Annonce à {n} utilisateur",
"plural": "Annonce à {n} utilisateurs"
},
"enabledUser": {
"plural": "{n} utilisateurs activés.",
"singular": "{n} utilisateur activé."
},
"extendExpiry": {
"singular": "Prolonger l'expiration pour {n} utilisateur",
"plural": "Prolonger l'expiration pour {n} utilisateurs"
},
"extendedExpiry": {
"singular": "Expiration prolongée pour {n} utilisateur.",
"plural": "Expiration prolongée pour {n} utilisateurs."
},
"disableUsers": {
"singular": "Désactiver {n} utilisateur",
"plural": "Désactiver {n} utilisateurs"
},
"reEnableUsers": {
"singular": "Ré-activer {n} utilisateur",
"plural": "Ré-activer {n} utilisateurs"
},
"disabledUser": {
"singular": "{n} utilisateur désactivé.",
"plural": "{n} utilisateurs désactivés."
}
}
}

141
lang/admin/id-id.json Normal file
View 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"
}
}
}

192
lang/admin/nl-nl.json Normal file
View File

@@ -0,0 +1,192 @@
{
"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 melding",
"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": "Onderwerp",
"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",
"donate": "Doneer",
"contactThrough": "Stuur bericht via:",
"sendPIN": "Vraag de gebruiker om onderstaande pincode naar de bot te sturen."
},
"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 welkomstbericht 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.",
"telegramVerified": "Telegram-account goedgekeurd.",
"updateAppliedRefresh": "Update toegepast, ververs alsjeblieft."
},
"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."
}
}
}

192
lang/admin/pt-br.json Normal file
View File

@@ -0,0 +1,192 @@
{
"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 mensagem 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",
"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",
"donate": "Doar",
"contactThrough": "Contato através:",
"sendPIN": "Peça ao usuário para enviar o PIN abaixo para o bot."
},
"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 mensagem 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.",
"telegramVerified": "Conta do Telegram verificada.",
"updateAppliedRefresh": "Atualização instalada, atualize."
},
"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
View 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."
}
}
}

22
lang/common/de-de.json Normal file
View File

@@ -0,0 +1,22 @@
{
"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",
"linkTelegram": "Link Telegram",
"contactEmail": "Kontakt über E-Mail",
"contactTelegram": "Kontakt über Telegram"
}
}

19
lang/common/el-gr.json Normal file
View 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
View File

@@ -0,0 +1,5 @@
{
"meta": {
"name": "English (GB)"
}
}

26
lang/common/en-us.json Normal file
View File

@@ -0,0 +1,26 @@
{
"meta": {
"name": "English (US)"
},
"strings": {
"username": "Username",
"password": "Password",
"emailAddress": "Email Address",
"name": "Name",
"submit": "Submit",
"send": "Send",
"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",
"linkDiscord": "Link Discord",
"linkMatrix": "Link Matrix",
"contactDiscord": "Contact through Discord",
"theme": "Theme"
}
}

19
lang/common/es-es.json Normal file
View 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"
}
}

23
lang/common/fr-fr.json Normal file
View File

@@ -0,0 +1,23 @@
{
"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",
"copied": "Copié",
"linkTelegram": "Lien Telegram",
"contactEmail": "Contact par e-mail",
"contactTelegram": "Contact par Telegram"
}
}

18
lang/common/id-id.json Normal file
View 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"
}
}

22
lang/common/nl-nl.json Normal file
View File

@@ -0,0 +1,22 @@
{
"meta": {
"name": "Nederlands (NL)"
},
"strings": {
"username": "Gebruikersnaam",
"name": "Naam",
"password": "Wachtwoord",
"emailAddress": "E-mailadres",
"submit": "Verstuur",
"success": "Succes",
"error": "Fout",
"copy": "Kopiëer",
"theme": "Thema",
"time24h": "24u-formaat",
"time12h": "12u-formaat",
"copied": "Gekopieerd",
"linkTelegram": "Koppel Telegram",
"contactEmail": "Stuur e-mailbericht",
"contactTelegram": "Stuur Telegram-bericht"
}
}

22
lang/common/pt-br.json Normal file
View File

@@ -0,0 +1,22 @@
{
"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",
"linkTelegram": "Link Telegram",
"contactEmail": "Contato por Email",
"contactTelegram": "Contato pelo Telegram"
}
}

18
lang/common/sv-se.json Normal file
View 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"
}
}

77
lang/email/de-de.json Normal file
View File

@@ -0,0 +1,77 @@
{
"meta": {
"name": "Deutsch (DE)"
},
"strings": {
"ifItWasNotYou": "Wenn du das nicht warst, ignoriere bitte dies.",
"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",
"ifItWasYouLink": "Wenn du das warst, klick auf den Link unten."
},
"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": "Willkommen",
"yourAccountWillExpire": "Dein Konto läuft am {date} ab."
},
"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."
},
"userDisabled": {
"name": "Benutzer deaktiviert",
"title": "Dein Konto wurde deaktiviert - Jellyfin",
"yourAccountWasDisabled": "Dein Konto wurde deaktiviert."
},
"userEnabled": {
"name": "Benutzer aktiviert",
"title": "Dein Konto wurde wieder freigeschaltet - Jellyfin",
"yourAccountWasEnabled": "Dein Konto wurde wieder aktiviert."
}
}

77
lang/email/el-gr.json Normal file
View 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
View File

@@ -0,0 +1,5 @@
{
"meta": {
"name": "English (GB)"
}
}

View File

@@ -2,40 +2,76 @@
"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 {n}.",
"name": "Name",
"emailAddress": "Address",
"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 {n} expired at {n}.",
"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",
"helloUser": "Hi {n},",
"someoneHasRequestedReset": "Someone has recently requested a password reset on Jellyfin.",
"ifItWasYou": "If this was you, enter the pin below into the prompt.",
"codeExpiry": "The code will expire on {n}, at {n} UTC, which is in {n}.",
"ifItWasNotYou": "If this wasn't you, please ignore this email.",
"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.",
"reason": "Reason"
"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 {n}, at {n}, which is in {n}, so act quick.",
"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
View 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."
}
}

View File

@@ -1,42 +1,78 @@
{
"meta": {
"name": "Francais (FR)",
"name": "Français (FR)",
"author": "https://github.com/Cornichon420"
},
"strings": {
"ifItWasNotYou": "Si ce n'était pas toi, tu peux ignorer ceci.",
"reason": "Motif",
"helloUser": "Salut {username},"
},
"userCreated": {
"title": "Notification : Utilisateur créé",
"aUserWasCreated": "Un utilisateur a été créé avec ce code {n}",
"name": "Nom",
"emailAddress": "Adresse",
"aUserWasCreated": "Un utilisateur a été créé avec ce code {code}.",
"time": "Date",
"notificationNotice": ""
"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 {n} a expiré à {n}.",
"notificationNotice": ""
"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",
"helloUser": "Salut {n},",
"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 {n}, à {n} UTC, soit dans {n}.",
"ifItWasNotYou": "Si ce n'était pas toi, tu peux ignorer ce mail.",
"pin": "PIN"
"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é.",
"reason": "Motif"
"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 {n}, à {n}, soit dans {n}, alors fais vite !",
"linkButton": "Lien"
"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": "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
View 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
View 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
View File

@@ -0,0 +1,77 @@
{
"meta": {
"name": "Nederlands (NL)"
},
"strings": {
"ifItWasNotYou": "Als jij dit niet was, negeer dit dan alsjeblieft.",
"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": "Welkom",
"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
View 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
View 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."
}
}

52
lang/form/de-de.json Normal file
View File

@@ -0,0 +1,52 @@
{
"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.",
"sendPIN": "Sende die untenstehende PIN an den Bot und komm dann hierher zurück, um dein Konto zu verbinden."
},
"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.",
"telegramVerified": "Telegram-Konto verifiziert.",
"errorTelegramVerification": "Verifizierung von Telegram erforderlich.",
"errorInvalidPIN": "Telegram PIN ist ungültig."
}
}

48
lang/form/el-gr.json Normal file
View 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
View File

@@ -0,0 +1,5 @@
{
"meta": {
"name": "English (GB)"
}
}

View File

@@ -15,27 +15,43 @@
"passwordRequirementsHeader": "Password Requirements",
"successHeader": "Success!",
"successContinueButton": "Continue",
"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"
}
"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.",
"sendPINDiscord": "Type {command} in {server_channel} on Discord, then send the PIN below via DM to the bot.",
"matrixEnterUser": "Enter your User ID, press submit, and a PIN will be sent to you. Enter it here to continue."
},
"notifications": {
"errorUserExists": "User already exists.",
"errorInvalidCode": "Invalid invite code.",
"errorTelegramVerification": "Telegram verification required.",
"errorDiscordVerification": "Discord verification required.",
"errorMatrixVerification": "Matrix verification required.",
"errorInvalidPIN": "PIN is invalid.",
"errorUnknown": "Unknown error.",
"verified": "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
View 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"
}
}
}

View File

@@ -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,38 @@
"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.",
"yourAccountIsValidUntil": "Votre compte sera valide jusqu'au {date}.",
"sendPIN": "Envoyez le code PIN ci-dessous au bot, puis revenez ici pour lier votre compte."
},
"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 dinvitation non valide.",
"errorTelegramVerification": "Vérification Telegram requise.",
"errorInvalidPIN": "PIN Telegram invalide.",
"telegramVerified": "Compte Telegram vérifié."
}
}

47
lang/form/id-id.json Normal file
View 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
View 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"
}
}
}

View File

@@ -6,7 +6,7 @@
"pageTitle": "Maak Jellyfin account aan",
"createAccountHeader": "Account aanmaken",
"accountDetails": "Details",
"emailAddress": "Email",
"emailAddress": "E-mail",
"username": "Gebruikersnaam",
"password": "Wachtwoord",
"reEnterPassword": "Bevestig wachtwoord",
@@ -15,27 +15,38 @@
"passwordRequirementsHeader": "Wachtwoordvereisten",
"successHeader": "Succes!",
"successContinueButton": "Doorgaan",
"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"
}
"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}.",
"sendPIN": "Stuur onderstaande pincode naar de bot, en kom daarna hier terug om je account te koppelen."
},
"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.",
"telegramVerified": "Telegram-account goedgekeurd.",
"errorTelegramVerification": "Telegram-verificatie nodig.",
"errorInvalidPIN": "Telegram pincode is ongeldig."
}
}

52
lang/form/pt-br.json Normal file
View File

@@ -0,0 +1,52 @@
{
"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": "Confirmação por e-mail",
"confirmationRequiredMessage": "Verifique sua caixa de email para finalizar o cadastro.",
"yourAccountIsValidUntil": "Sua conta é válida até {date}.",
"sendPIN": "Envie o PIN abaixo para o bot e volte aqui para vincular sua conta."
},
"notifications": {
"errorUserExists": "Esse usuário já existe.",
"errorInvalidCode": "Código do convite invalido.",
"telegramVerified": "Conta do Telegram verificada.",
"errorInvalidPIN": "O PIN do telegram é inválido.",
"errorTelegramVerification": "Requer a verificação do telegram."
},
"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
View 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/de-DE.json Normal file
View File

@@ -0,0 +1,13 @@
{
"meta": {
"name": "Deutsch (DE)"
},
"strings": {
"passwordReset": "Passwort zurücksetzen",
"resetFailed": "Zurücksetzen des Passworts fehlgeschlagen",
"tryAgain": "Bitte versuche es erneut.",
"youCanLogin": "Du kannst dich nun mit dem unten stehenden Code als Passwort anmelden.",
"youCanLoginOmbi": "Du kannst dich jetzt bei Jellyfin und Ombi mit dem unten stehenden Code als Passwort anmelden.",
"changeYourPassword": "Achte darauf, dass du dein Passwort nach der Anmeldung änderst."
}
}

Some files were not shown because too many files have changed in this diff Show More