mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-09-07 21:10:11 +00:00
Compare commits
32 Commits
ebb4f0b052
...
a3b69d6565
Author | SHA1 | Date | |
---|---|---|---|
|
a3b69d6565 | ||
43e36ee6fc | |||
53c9569a37 | |||
c39a9e80e7 | |||
3d0f756264 | |||
|
85de1c97ff | ||
2c8afecfbb | |||
4924700c52 | |||
e2c24a2593 | |||
31b7ede665 | |||
dba7d0bd4e | |||
73cfa5bef2 | |||
6909477f45 | |||
701d1305d3 | |||
08498074ed | |||
|
28d321986a | ||
|
943d523f3f | ||
|
8f88b6aaa2 | ||
|
7f60598d4a | ||
|
18e82fd04b | ||
|
d7d7146e12 | ||
|
aaa5217398 | ||
|
9610b89fa5 | ||
|
9809611d0d | ||
|
b1e38ba15d | ||
|
35a765aa01 | ||
|
82411f1868 | ||
|
b0e01144f4 | ||
|
04f354b3d1 | ||
|
918f3ad588 | ||
635c2be32c | |||
|
7db12fdbe7 |
@ -54,6 +54,7 @@ builds:
|
||||
goos:
|
||||
- linux
|
||||
- darwin
|
||||
- windows
|
||||
goarch:
|
||||
- arm
|
||||
- arm64
|
||||
|
@ -76,6 +76,7 @@ func (app *appContext) loadConfig() error {
|
||||
|
||||
app.MustSetValue("smtp", "hello_hostname", "localhost")
|
||||
app.MustSetValue("smtp", "cert_validation", "true")
|
||||
app.MustSetValue("smtp", "auth_type", "4")
|
||||
|
||||
sc := app.config.Section("discord").Key("start_command").MustString("start")
|
||||
app.config.Section("discord").Key("start_command").SetValue(strings.TrimPrefix(strings.TrimPrefix(sc, "/"), "!"))
|
||||
|
@ -918,6 +918,22 @@
|
||||
"type": "bool",
|
||||
"value": true,
|
||||
"description": "Warning, disabling this makes you much more vulnerable to man-in-the-middle attacks"
|
||||
},
|
||||
"auth_type": {
|
||||
"name": "Authentication type",
|
||||
"required": false,
|
||||
"requires_restart": false,
|
||||
"advanced": false,
|
||||
"type": "select",
|
||||
"options": [
|
||||
["0", "Plain"],
|
||||
["1", "Login"],
|
||||
["2", "CRAM-MD5"],
|
||||
["3", "None"],
|
||||
["4", "Auto"]
|
||||
],
|
||||
"value": 4,
|
||||
"description": "SMTP authentication method"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
42
daemon.go
42
daemon.go
@ -1,6 +1,10 @@
|
||||
package main
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/hrfee/mediabrowser"
|
||||
)
|
||||
|
||||
// clearEmails removes stored emails for users which no longer exist.
|
||||
// meant to be called with other such housekeeping functions, so assumes
|
||||
@ -9,11 +13,14 @@ func (app *appContext) clearEmails() {
|
||||
app.debug.Println("Housekeeping: removing unused email addresses")
|
||||
emails := app.storage.GetEmails()
|
||||
for _, email := range emails {
|
||||
_, status, err := app.jf.UserByID(email.JellyfinID, false)
|
||||
if status == 200 && err == nil {
|
||||
_, _, err := app.jf.UserByID(email.JellyfinID, false)
|
||||
// Make sure the user doesn't exist, and no other error has occured
|
||||
switch err.(type) {
|
||||
case mediabrowser.ErrUserNotFound:
|
||||
app.storage.DeleteEmailsKey(email.JellyfinID)
|
||||
default:
|
||||
continue
|
||||
}
|
||||
app.storage.DeleteEmailsKey(email.JellyfinID)
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,11 +29,14 @@ func (app *appContext) clearDiscord() {
|
||||
app.debug.Println("Housekeeping: removing unused Discord IDs")
|
||||
discordUsers := app.storage.GetDiscord()
|
||||
for _, discordUser := range discordUsers {
|
||||
_, status, err := app.jf.UserByID(discordUser.JellyfinID, false)
|
||||
if status == 200 && err == nil {
|
||||
_, _, err := app.jf.UserByID(discordUser.JellyfinID, false)
|
||||
// Make sure the user doesn't exist, and no other error has occured
|
||||
switch err.(type) {
|
||||
case mediabrowser.ErrUserNotFound:
|
||||
app.storage.DeleteDiscordKey(discordUser.JellyfinID)
|
||||
default:
|
||||
continue
|
||||
}
|
||||
app.storage.DeleteDiscordKey(discordUser.JellyfinID)
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,11 +45,14 @@ func (app *appContext) clearMatrix() {
|
||||
app.debug.Println("Housekeeping: removing unused Matrix IDs")
|
||||
matrixUsers := app.storage.GetMatrix()
|
||||
for _, matrixUser := range matrixUsers {
|
||||
_, status, err := app.jf.UserByID(matrixUser.JellyfinID, false)
|
||||
if status == 200 && err == nil {
|
||||
_, _, err := app.jf.UserByID(matrixUser.JellyfinID, false)
|
||||
// Make sure the user doesn't exist, and no other error has occured
|
||||
switch err.(type) {
|
||||
case mediabrowser.ErrUserNotFound:
|
||||
app.storage.DeleteMatrixKey(matrixUser.JellyfinID)
|
||||
default:
|
||||
continue
|
||||
}
|
||||
app.storage.DeleteMatrixKey(matrixUser.JellyfinID)
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,11 +61,14 @@ func (app *appContext) clearTelegram() {
|
||||
app.debug.Println("Housekeeping: removing unused Telegram IDs")
|
||||
telegramUsers := app.storage.GetTelegram()
|
||||
for _, telegramUser := range telegramUsers {
|
||||
_, status, err := app.jf.UserByID(telegramUser.JellyfinID, false)
|
||||
if status == 200 && err == nil {
|
||||
_, _, err := app.jf.UserByID(telegramUser.JellyfinID, false)
|
||||
// Make sure the user doesn't exist, and no other error has occured
|
||||
switch err.(type) {
|
||||
case mediabrowser.ErrUserNotFound:
|
||||
app.storage.DeleteTelegramKey(telegramUser.JellyfinID)
|
||||
default:
|
||||
continue
|
||||
}
|
||||
app.storage.DeleteTelegramKey(telegramUser.JellyfinID)
|
||||
}
|
||||
}
|
||||
|
||||
|
7
email.go
7
email.go
@ -92,7 +92,8 @@ func NewEmailer(app *appContext) *Emailer {
|
||||
if app.proxyEnabled {
|
||||
proxyConf = &app.proxyConfig
|
||||
}
|
||||
err := emailer.NewSMTP(app.config.Section("smtp").Key("server").String(), app.config.Section("smtp").Key("port").MustInt(465), username, password, sslTLS, app.config.Section("smtp").Key("ssl_cert").MustString(""), app.config.Section("smtp").Key("hello_hostname").String(), app.config.Section("smtp").Key("cert_validation").MustBool(true), proxyConf)
|
||||
authType := sMail.AuthType(app.config.Section("smtp").Key("auth_type").MustInt(4))
|
||||
err := emailer.NewSMTP(app.config.Section("smtp").Key("server").String(), app.config.Section("smtp").Key("port").MustInt(465), username, password, sslTLS, app.config.Section("smtp").Key("ssl_cert").MustString(""), app.config.Section("smtp").Key("hello_hostname").String(), app.config.Section("smtp").Key("cert_validation").MustBool(true), authType, proxyConf)
|
||||
if err != nil {
|
||||
app.err.Printf("Error while initiating SMTP mailer: %v", err)
|
||||
}
|
||||
@ -118,7 +119,7 @@ type SMTP struct {
|
||||
}
|
||||
|
||||
// NewSMTP returns an SMTP emailClient.
|
||||
func (emailer *Emailer) NewSMTP(server string, port int, username, password string, sslTLS bool, certPath string, helloHostname string, validateCertificate bool, proxy *easyproxy.ProxyConfig) (err error) {
|
||||
func (emailer *Emailer) NewSMTP(server string, port int, username, password string, sslTLS bool, certPath string, helloHostname string, validateCertificate bool, authType sMail.AuthType, proxy *easyproxy.ProxyConfig) (err error) {
|
||||
sender := &SMTP{}
|
||||
sender.Client = sMail.NewSMTPClient()
|
||||
if sslTLS {
|
||||
@ -127,7 +128,7 @@ func (emailer *Emailer) NewSMTP(server string, port int, username, password stri
|
||||
sender.Client.Encryption = sMail.EncryptionSTARTTLS
|
||||
}
|
||||
if username != "" || password != "" {
|
||||
sender.Client.Authentication = sMail.AuthLogin
|
||||
sender.Client.Authentication = authType
|
||||
sender.Client.Username = username
|
||||
sender.Client.Password = password
|
||||
}
|
||||
|
@ -645,7 +645,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<input type="search" class="field ~neutral @low input search ml-2 mr-2" id="accounts-search" placeholder="{{ .strings.search }}">
|
||||
<span class="button ~neutral @low center -ml-8" id="accounts-search-clear" aria-label="{{ .strings.clearSearch }}" text="{{ .strings.clearSearch }}"><i class="ri-close-line"></i></span>
|
||||
<span class="button ~neutral @low center ml-[-2.64rem] rounded-s-none accounts-search-clear" aria-label="{{ .strings.clearSearch }}" text="{{ .strings.clearSearch }}"><i class="ri-close-line"></i></span>
|
||||
</div>
|
||||
<div class="supra py-1 sm hidden" id="accounts-search-options-header">{{ .strings.searchOptions }}</div>
|
||||
<div class="row -mx-2 mb-2">
|
||||
@ -708,6 +708,14 @@
|
||||
</thead>
|
||||
<tbody id="accounts-list"></tbody>
|
||||
</table>
|
||||
<div class="unfocused h-[100%] my-3" id="accounts-not-found">
|
||||
<div class="flex flex-col h-[100%] justify-center items-center">
|
||||
<span class="text-2xl font-medium italic mb-3">{{ .strings.noResultsFound }}</span>
|
||||
<button class="button ~neutral @low accounts-search-clear">
|
||||
<span class="mr-2">{{ .strings.clearSearch }}</span><i class="ri-close-line"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -729,11 +737,25 @@
|
||||
</div>
|
||||
<div class="flex flex-col md:flex-row gap-3">
|
||||
<div class="card @low dark:~d_neutral col" id="settings-sidebar">
|
||||
<div class="flex-expand">
|
||||
<input type="search" class="field ~neutral @low input settings-section-button justify-between mb-2" id="settings-search" placeholder="{{ .strings.search }}">
|
||||
<button class="button ~neutral @low center -ml-10 rounded-s-none mb-2 settings-search-clear" aria-label="{{ .strings.clearSearch }}" text="{{ .strings.clearSearch }}"><i class="ri-close-line"></i></button>
|
||||
</div>
|
||||
<aside class="aside sm ~urge dark:~d_info mb-2 @low" id="settings-message">Note: <span class="badge ~critical">*</span> indicates a required field, <span class="badge ~info dark:~d_warning">R</span> indicates changes require a restart.</aside>
|
||||
<span class="button ~neutral @low settings-section-button justify-between mb-2" id="setting-about"><span class="flex">{{ .strings.aboutProgram }} <i class="ri-information-line ml-2"></i></span></span>
|
||||
<span class="button ~neutral @low settings-section-button justify-between mb-2" id="setting-profiles"><span class="flex">{{ .strings.userProfiles }} <i class="ri-user-line ml-2"></i></span></span>
|
||||
</div>
|
||||
<div class="card ~neutral @low col overflow" id="settings-panel"></div>
|
||||
<div class="card ~neutral @low col overflow" id="settings-panel">
|
||||
<div class="settings-section unfocused h-[100%]" id="settings-not-found">
|
||||
<div class="flex flex-col h-[100%] justify-center items-center">
|
||||
<span class="text-2xl font-medium italic mb-2">{{ .strings.noResultsFound }}</span>
|
||||
<span class="mb-2 px-12 text-center">{{ .strings.settingsMaybeUnderAdvanced }}</span>
|
||||
<button class="button ~neutral @low settings-search-clear">
|
||||
<span class="mr-2">{{ .strings.clearSearch }}</span><i class="ri-close-line"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -122,6 +122,32 @@
|
||||
</select>
|
||||
</div>
|
||||
</label>
|
||||
<span class="heading">{{ .lang.Proxy.title }}</span>
|
||||
<p class="content my-2" id="proxy-description">{{ .lang.Proxy.description }}</p>
|
||||
<label class="row switch pb-4">
|
||||
<input type="checkbox" class="mr-2" id="advanced-proxy"><span>{{ .lang.Strings.enabled }}</span>
|
||||
</label>
|
||||
<label class="label">
|
||||
<span>{{ .lang.Proxy.protocol }}</span>
|
||||
<div class="select ~neutral @low mt-4 mb-2">
|
||||
<select id="advanced-proxy_protocol">
|
||||
<option value="http">HTTP</option>
|
||||
<option value="socks">SOCKS5</option>
|
||||
</select>
|
||||
</div>
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-4">{{ .lang.Proxy.address }}</span>
|
||||
<input type="text" class="input ~neutral @low mt-4 mb-2" id="advanced-proxy_address">
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-4">{{ .lang.Strings.username }}</span>
|
||||
<input type="text" class="input ~neutral @low mt-4 mb-2" id="advanced-proxy_user">
|
||||
</label>
|
||||
<label class="label">
|
||||
<span class="mt-4">{{ .lang.Strings.password }}</span>
|
||||
<input type="text" class="input ~neutral @low mt-4 mb-2" id="advanced-proxy_password">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<section class="section ~neutral banner footer flex-expand middle">
|
||||
|
1
lang.go
1
lang.go
@ -116,6 +116,7 @@ type setupLang struct {
|
||||
EndPage langSection `json:"endPage"`
|
||||
General langSection `json:"general"`
|
||||
Updates langSection `json:"updates"`
|
||||
Proxy langSection `json:"proxy"`
|
||||
Language langSection `json:"language"`
|
||||
Login langSection `json:"login"`
|
||||
JellyfinEmby langSection `json:"jellyfinEmby"`
|
||||
|
229
lang/admin/cs-cz.json
Normal file
229
lang/admin/cs-cz.json
Normal file
@ -0,0 +1,229 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Čeština (CZ)"
|
||||
},
|
||||
"strings": {
|
||||
"invites": "Pozvánky",
|
||||
"invite": "Pozvat",
|
||||
"accounts": "Účty",
|
||||
"settings": "Nastavení",
|
||||
"inviteMonths": "Měsíce",
|
||||
"inviteDays": "Dny",
|
||||
"inviteHours": "Hodiny",
|
||||
"inviteMinutes": "Minut",
|
||||
"inviteNumberOfUses": "Počet použití",
|
||||
"inviteDuration": "Doba trvání pozvánky",
|
||||
"warning": "Varování",
|
||||
"inviteInfiniteUsesWarning": "pozvánky s nekonečným využitím mohou být zneužity",
|
||||
"inviteSendToEmail": "Poslat komu",
|
||||
"create": "Vytvořit",
|
||||
"apply": "Aplikovat",
|
||||
"select": "Vybrat",
|
||||
"name": "Název",
|
||||
"date": "Datum",
|
||||
"setExpiry": "Nastavit expiraci",
|
||||
"updates": "Aktualizace",
|
||||
"update": "Aktualizace",
|
||||
"download": "Stažení",
|
||||
"search": "Vyhledávání",
|
||||
"advancedSettings": "Pokročilé nastavení",
|
||||
"lastActiveTime": "Naposled aktivní",
|
||||
"from": "Z",
|
||||
"after": "Po",
|
||||
"before": "Před",
|
||||
"user": "Uživatel",
|
||||
"userExpiry": "Vypršení platnosti",
|
||||
"userExpiryDescription": "Zadanou dobu po každé registraci jfa-go smaže/zakáže účet. Toto chování můžete změnit v nastavení.",
|
||||
"aboutProgram": "O",
|
||||
"version": "Verze",
|
||||
"commitNoun": "Zavázat se",
|
||||
"newUser": "Nový uživatel",
|
||||
"profile": "Profil",
|
||||
"unknown": "Neznámý",
|
||||
"label": "Štítek",
|
||||
"userLabel": "Uživatelský štítek",
|
||||
"userLabelDescription": "Štítek, který se použije pro uživatele vytvořené pomocí této pozvánky.",
|
||||
"logs": "Protokoly",
|
||||
"announce": "Oznámit",
|
||||
"templates": "Šablony",
|
||||
"subject": "Předmět",
|
||||
"message": "Zpráva",
|
||||
"variables": "Proměnné",
|
||||
"conditionals": "Podmínky",
|
||||
"preview": "Náhled",
|
||||
"reset": "Resetovat",
|
||||
"donate": "Darovat",
|
||||
"unlink": "Odpojit účet",
|
||||
"sendPWR": "Odeslat resetování hesla",
|
||||
"contactThrough": "Kontakt přes:",
|
||||
"extendExpiry": "Prodloužit platnost",
|
||||
"sendPWRManual": "Uživatel {n} nemá žádný způsob kontaktu, stisknutím tlačítka Kopírovat získáte odkaz, který mu chcete poslat.",
|
||||
"sendPWRSuccess": "Odkaz pro resetování hesla byl odeslán.",
|
||||
"sendPWRSuccessManual": "Pokud jej uživatel neobdržel, stisknutím tlačítka Kopírovat získáte odkaz, který mu můžete ručně odeslat.",
|
||||
"sendPWRValidFor": "Odkaz je platný 30m.",
|
||||
"customizeMessages": "Přizpůsobit zprávy",
|
||||
"customizeMessagesDescription": "Pokud nechcete používat šablony zpráv jfa-go, můžete si vytvořit vlastní pomocí Markdown.",
|
||||
"markdownSupported": "Markdown je podporován.",
|
||||
"modifySettings": "Upravit nastavení",
|
||||
"modifySettingsDescription": "Použít nastavení ze stávajícího profilu nebo je získat přímo od uživatele.",
|
||||
"enableReferrals": "Povolit doporučení",
|
||||
"disableReferrals": "Zakázat doporučení",
|
||||
"enableReferralsDescription": "Poskytněte uživatelům osobní doporučující odkaz podobný pozvánce, kterou můžete poslat přátelům/rodině. Lze je získat ze šablony doporučení v profilu nebo z existující pozvánky.",
|
||||
"enableReferralsProfileDescription": "Poskytněte uživatelům vytvořeným pomocí tohoto profilu osobní doporučující odkaz podobný pozvánce, aby jej poslali přátelům/rodině. Vytvořte pozvánku s požadovaným nastavením a poté ji vyberte zde. Každé doporučení pak bude založeno na této pozvánce. Po dokončení můžete pozvánku smazat.",
|
||||
"applyHomescreenLayout": "Použít rozložení domovské obrazovky",
|
||||
"sendDeleteNotificationEmail": "Odeslat zprávu s upozorněním",
|
||||
"sendDeleteNotifiationExample": "Váš účet byl smazán.",
|
||||
"settingsRestart": "Restartovat",
|
||||
"settingsRestarting": "Restartování…",
|
||||
"settingsRestartRequired": "Je potřeba restart",
|
||||
"settingsRestartRequiredDescription": "K použití některých změn, které jste změnili, je nutný restart. Restartovat hned nebo později?",
|
||||
"settingsApplyRestartLater": "Použít, restartovat později",
|
||||
"settingsApplyRestartNow": "Použít a restartovat",
|
||||
"settingsApplied": "Nastavení byla použita.",
|
||||
"settingsRefreshPage": "Obnovte stránku během několika sekund.",
|
||||
"settingsRequiredOrRestartMessage": "Poznámka: {n} označuje povinné pole, {n} označuje, že změny vyžadují restart.",
|
||||
"settingsSave": "Uložit",
|
||||
"ombiProfile": "Ombi uživatelský profil",
|
||||
"ombiUserDefaultsDescription": "Vytvořte uživatele Ombi a nakonfigurujte jej, poté jej vyberte níže. Když je tento profil vybrán, jeho nastavení/oprávnění budou uložena a použita pro nové uživatele Ombi vytvořené jfa-go.",
|
||||
"userProfiles": "Uživatelské profily",
|
||||
"userProfilesDescription": "Profily se použijí pro uživatele, když si vytvoří účet. Profil zahrnuje přístupová práva ke knihovně a rozvržení domovské obrazovky.",
|
||||
"userProfilesIsDefault": "Výchozí",
|
||||
"userProfilesLibraries": "Knihovny",
|
||||
"addProfile": "Přidat profil",
|
||||
"addProfileDescription": "Vytvořte uživatele Jellyfin a nakonfigurujte jej, poté jej vyberte níže. Když se tento profil použije na pozvánku, vytvoří se noví uživatelé s nastavením.",
|
||||
"addProfileNameOf": "Jméno profilu",
|
||||
"addProfileStoreHomescreenLayout": "Uložit rozložení domovské obrazovky",
|
||||
"inviteNoUsersCreated": "Ještě žádný!",
|
||||
"inviteUsersCreated": "Vytvoření uživatelé",
|
||||
"inviteNoProfile": "Žádný profil",
|
||||
"inviteDateCreated": "Vytvořeno",
|
||||
"inviteNoInvites": "Žádný",
|
||||
"inviteExpiresInTime": "Platnost vyprší za {n}",
|
||||
"notifyEvent": "Upozornit na:",
|
||||
"notifyInviteExpiry": "Při vypršení platnosti",
|
||||
"notifyUserCreation": "Při vytvoření uživatele",
|
||||
"sendPIN": "Požádejte uživatele, aby robotovi zaslal níže uvedený PIN.",
|
||||
"searchDiscordUser": "Začněte psát uživatelské jméno Discord a vyhledejte uživatele.",
|
||||
"findDiscordUser": "Najít uživatele Discordu",
|
||||
"linkMatrixDescription": "Zadejte uživatelské jméno a heslo uživatele, který chcete použít jako robot. Po odeslání se aplikace restartuje.",
|
||||
"matrixHomeServer": "Adresa domovského serveru",
|
||||
"saveAsTemplate": "Uložit jako šablonu",
|
||||
"deleteTemplate": "Smazat šablonu",
|
||||
"templateEnterName": "Zadejte název pro uložení této šablony.",
|
||||
"accessJFA": "Přístup k jfa-go",
|
||||
"accessJFASettings": "Nelze změnit, protože v Nastavení > Obecné bylo nastaveno \"Pouze správce\" nebo \"Povolit vše\".",
|
||||
"sortingBy": "Řazení podle",
|
||||
"filters": "Filtry",
|
||||
"clickToRemoveFilter": "Kliknutím tento filtr odstraníte.",
|
||||
"clearSearch": "Vymazat vyhledávání",
|
||||
"actions": "Akce",
|
||||
"searchOptions": "Možnosti hledání",
|
||||
"matchText": "Shoda textu",
|
||||
"jellyfinID": "Jellyfin ID",
|
||||
"userPageLogin": "Uživatelská stránka: Přihlášení",
|
||||
"userPagePage": "Uživatelská stránka: Stránka",
|
||||
"buildTime": "Čas sestavení",
|
||||
"builtBy": "Postaven",
|
||||
"loginNotAdmin": "Nejste správce?"
|
||||
},
|
||||
"notifications": {
|
||||
"changedEmailAddress": "Změněna e-mailová adresa uživatele {n}.",
|
||||
"userCreated": "Uživatel {n} byl vytvořen.",
|
||||
"createProfile": "Vytvořen profil {n}.",
|
||||
"saveSettings": "Nastavení byla uložena",
|
||||
"saveEmail": "Email byl uložen.",
|
||||
"sentAnnouncement": "Oznámení odesláno.",
|
||||
"savedAnnouncement": "Oznámení uloženo.",
|
||||
"setOmbiProfile": "Uložený ombi profil.",
|
||||
"updateApplied": "Aktualizace byla použita, restartujte prosím.",
|
||||
"updateAppliedRefresh": "Aktualizace byla použita, obnovte ji.",
|
||||
"telegramVerified": "Účet telegramu ověřen.",
|
||||
"accountConnected": "Účet připojen.",
|
||||
"referralsEnabled": "Doporučení povolena.",
|
||||
"errorSettingsAppliedNoHomescreenLayout": "Nastavení byla použita, ale použití rozvržení domovské obrazovky mohlo selhat.",
|
||||
"errorHomescreenAppliedNoSettings": "Bylo použito rozvržení domovské obrazovky, ale použití nastavení mohlo selhat.",
|
||||
"errorSettingsFailed": "Aplikace se nezdařila.",
|
||||
"errorSaveEmail": "Uložení e-mailu se nezdařilo.",
|
||||
"errorBlankFields": "Pole zůstala prázdná",
|
||||
"errorDeleteProfile": "Smazání profilu {n} se nezdařilo",
|
||||
"errorLoadProfiles": "Načtení profilů se nezdařilo.",
|
||||
"errorCreateProfile": "Nepodařilo se vytvořit profil {n}",
|
||||
"errorSetDefaultProfile": "Nepodařilo se nastavit výchozí profil.",
|
||||
"errorLoadUsers": "Uživatele se nepodařilo načíst.",
|
||||
"errorLoadSettings": "Nastavení se nepodařilo načíst.",
|
||||
"errorSetOmbiProfile": "Uložení profilu ombi se nezdařilo.",
|
||||
"errorLoadOmbiUsers": "Uživatele ombi se nepodařilo načíst.",
|
||||
"errorChangedEmailAddress": "E-mailovou adresu uživatele {n} se nepodařilo změnit.",
|
||||
"errorFailureCheckLogs": "Selhalo (zkontrolujte konzolu/protokoly)",
|
||||
"errorPartialFailureCheckLogs": "Částečná chyba (zkontrolujte konzolu/protokoly)",
|
||||
"errorUserCreated": "Nepodařilo se vytvořit uživatele {n}.",
|
||||
"errorSendWelcomeEmail": "Nepodařilo se odeslat uvítací zprávu (zkontrolujte konzolu/protokoly)",
|
||||
"errorApplyUpdate": "Aktualizaci se nepodařilo použít, zkuste to ručně.",
|
||||
"errorCheckUpdate": "Kontrola aktualizace se nezdařila.",
|
||||
"errorNoReferralTemplate": "Profil neobsahuje šablonu doporučení, přidejte si ji v nastavení.",
|
||||
"updateAvailable": "Je k dispozici nová aktualizace, zkontrolujte nastavení.",
|
||||
"noUpdatesAvailable": "Nejsou k dispozici žádné nové aktualizace."
|
||||
},
|
||||
"quantityStrings": {
|
||||
"modifySettingsFor": {
|
||||
"singular": "Upravit nastavení pro {n} uživatele",
|
||||
"plural": "Upravit nastavení pro {n} uživatelů"
|
||||
},
|
||||
"enableReferralsFor": {
|
||||
"singular": "Povolit doporučení pro {n} uživatele",
|
||||
"plural": "Povolit doporučení pro {n} uživatelů"
|
||||
},
|
||||
"deleteNUsers": {
|
||||
"singular": "Smazat {n} uživatele",
|
||||
"plural": "Smazat {n} uživatelů"
|
||||
},
|
||||
"disableUsers": {
|
||||
"singular": "Zakázat {n} uživatele",
|
||||
"plural": "Zakázat {n} uživatelů"
|
||||
},
|
||||
"reEnableUsers": {
|
||||
"singular": "Znovu povolte {n} uživatele",
|
||||
"plural": "Znovu povolit {n} uživatelů"
|
||||
},
|
||||
"addUser": {
|
||||
"singular": "Přidat uživatele",
|
||||
"plural": "Přidat uživatele"
|
||||
},
|
||||
"deleteUser": {
|
||||
"singular": "Smazat uživatele",
|
||||
"plural": "Smazat uživatele"
|
||||
},
|
||||
"deletedUser": {
|
||||
"singular": "Smazán {n} uživatel.",
|
||||
"plural": "Smazaní {n} uživatelé."
|
||||
},
|
||||
"disabledUser": {
|
||||
"singular": "Deaktivován {n} uživatel.",
|
||||
"plural": "Zakázaných {n} uživatelů."
|
||||
},
|
||||
"enabledUser": {
|
||||
"singular": "Povoleno {n} uživatele.",
|
||||
"plural": "Povolených {n} uživatelů."
|
||||
},
|
||||
"announceTo": {
|
||||
"singular": "Oznámeno {n} uživateli",
|
||||
"plural": "Oznámit {n} uživatelům"
|
||||
},
|
||||
"appliedSettings": {
|
||||
"singular": "Nastavení byla použita na {n} uživatele.",
|
||||
"plural": "Nastavení byla použita na {n} uživatelů."
|
||||
},
|
||||
"extendExpiry": {
|
||||
"singular": "Prodloužit platnost pro {n} uživatele",
|
||||
"plural": "Prodloužit platnost pro {n} uživatelů"
|
||||
},
|
||||
"setExpiry": {
|
||||
"singular": "Nastavit vypršení platnosti pro {n} uživatele",
|
||||
"plural": "Nastavit vypršení platnosti pro {n} uživatelů"
|
||||
},
|
||||
"extendedExpiry": {
|
||||
"singular": "Prodloužená platnost pro {n} uživatele.",
|
||||
"plural": "Prodloužená platnost pro {n} uživatelů."
|
||||
}
|
||||
}
|
||||
}
|
@ -55,6 +55,7 @@
|
||||
"donate": "Donate",
|
||||
"unlink": "Unlink Account",
|
||||
"sendPWR": "Send Password Reset",
|
||||
"noResultsFound": "No Results Found",
|
||||
"contactThrough": "Contact through:",
|
||||
"extendExpiry": "Extend expiry",
|
||||
"sendPWRManual": "User {n} has no method of contact, press copy to get a link to send to them.",
|
||||
@ -83,6 +84,10 @@
|
||||
"settingsRefreshPage": "Refresh the page in a few seconds.",
|
||||
"settingsRequiredOrRestartMessage": "Note: {n} indicates a required field, {n} indicates changes require a restart.",
|
||||
"settingsSave": "Save",
|
||||
"settingsHiddenDependency": "Matching settings are hidden because they depend on the value of another setting:",
|
||||
"settingsDependsOn": "{setting}: Depends on {dependency}",
|
||||
"settingsAdvancedMode": "{setting}: Advanced Settings must be enabled",
|
||||
"settingsMaybeUnderAdvanced": "Tip: You might find what you're looking for by enabling Advanced Settings.",
|
||||
"ombiProfile": "Ombi user profile",
|
||||
"ombiUserDefaultsDescription": "Create an Ombi user and configure it, then select it below. It's settings/permissions will be stored and applied to new Ombi users created by jfa-go when this profile is selected.",
|
||||
"userProfiles": "User Profiles",
|
||||
@ -122,7 +127,7 @@
|
||||
"jellyfinID": "Jellyfin ID",
|
||||
"userPageLogin": "User Page: Login",
|
||||
"userPagePage": "User Page: Page",
|
||||
"buildTime": "Build Time",
|
||||
"buildTime": "Build Time",
|
||||
"builtBy": "Built By",
|
||||
"loginNotAdmin": "Not an Admin?"
|
||||
},
|
||||
|
67
lang/common/cs-cz.json
Normal file
67
lang/common/cs-cz.json
Normal file
@ -0,0 +1,67 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Čeština (CZ)"
|
||||
},
|
||||
"strings": {
|
||||
"username": "Uživatelské jméno",
|
||||
"password": "Heslo",
|
||||
"emailAddress": "Emailová adresa",
|
||||
"name": "Název",
|
||||
"submit": "Odeslat",
|
||||
"send": "Poslat",
|
||||
"success": "Hotovo",
|
||||
"continue": "Pokračovat",
|
||||
"error": "Chyba",
|
||||
"copy": "Kopírovat",
|
||||
"copied": "Zkopírováno",
|
||||
"time24h": "Čas 24 hodin",
|
||||
"time12h": "Čas 12 hodin",
|
||||
"linkTelegram": "Link Telegram",
|
||||
"contactEmail": "Kontakt přes Email",
|
||||
"contactTelegram": "Kontakt přes Telegram",
|
||||
"linkDiscord": "Link Discord",
|
||||
"linkMatrix": "Link Matrix",
|
||||
"contactDiscord": "Kontakt přes Discord",
|
||||
"theme": "Téma",
|
||||
"refresh": "Obnovit",
|
||||
"required": "Požadované",
|
||||
"login": "Přihlásit se",
|
||||
"logout": "Odhlásit se",
|
||||
"admin": "Admin",
|
||||
"enabled": "Povoleno",
|
||||
"disabled": "Zakázáno",
|
||||
"reEnable": "Znovu povolit",
|
||||
"disable": "Zakázat",
|
||||
"contactMethods": "Kontaktní metody",
|
||||
"accountStatus": "Stav účtu",
|
||||
"notSet": "Nenastaveno",
|
||||
"expiry": "Uplynutí",
|
||||
"add": "Přidat",
|
||||
"edit": "Upravit",
|
||||
"delete": "Vymazat",
|
||||
"myAccount": "Můj účet",
|
||||
"referrals": "Doporučení",
|
||||
"inviteRemainingUses": "Zbývající použití"
|
||||
},
|
||||
"notifications": {
|
||||
"errorLoginBlank": "Uživatelské jméno a/nebo heslo zůstalo prázdné.",
|
||||
"errorConnection": "Nelze se připojit k jfa-go.",
|
||||
"errorUnknown": "Neznámá chyba.",
|
||||
"error401Unauthorized": "Neoprávněný. Zkuste stránku obnovit.",
|
||||
"errorSaveSettings": "Nastavení se nepodařilo uložit."
|
||||
},
|
||||
"quantityStrings": {
|
||||
"year": {
|
||||
"singular": "{n} rok",
|
||||
"plural": "{n} let"
|
||||
},
|
||||
"month": {
|
||||
"singular": "{n} měsíc",
|
||||
"plural": "{n} měsíců"
|
||||
},
|
||||
"day": {
|
||||
"singular": "{n} den",
|
||||
"plural": "{n} dní"
|
||||
}
|
||||
}
|
||||
}
|
77
lang/email/cs-cz.json
Normal file
77
lang/email/cs-cz.json
Normal file
@ -0,0 +1,77 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Čeština (CZ)"
|
||||
},
|
||||
"strings": {
|
||||
"ifItWasNotYou": "Pokud jste to nebyl vy, ignorujte to.",
|
||||
"helloUser": "Ahoj {username},",
|
||||
"reason": "Důvod"
|
||||
},
|
||||
"userCreated": {
|
||||
"name": "Vytvoření uživatele",
|
||||
"title": "Upozornění: Uživatel vytvořen",
|
||||
"aUserWasCreated": "Uživatel byl vytvořen pomocí kódu {code}.",
|
||||
"time": "Čas",
|
||||
"notificationNotice": "Poznámka: Zprávy s upozorněním lze přepínat na řídicím panelu správce."
|
||||
},
|
||||
"inviteExpiry": {
|
||||
"name": "Platnost pozvánky",
|
||||
"title": "Upozornění: Platnost pozvánky vypršela",
|
||||
"inviteExpired": "Platnost pozvánky vypršela.",
|
||||
"expiredAt": "Platnost kódu {code} vypršela v {time}.",
|
||||
"notificationNotice": "Poznámka: Zprávy s upozorněním lze přepínat na řídicím panelu správce."
|
||||
},
|
||||
"passwordReset": {
|
||||
"name": "Resetovat heslo",
|
||||
"title": "Požadováno resetování hesla - Jellyfin",
|
||||
"someoneHasRequestedReset": "Někdo nedávno požádal o reset hesla na Jellyfin.",
|
||||
"ifItWasYou": "Pokud jste to byli vy, zadejte do výzvy níže uvedený kód PIN.",
|
||||
"ifItWasYouLink": "Pokud jste to byli vy, klikněte na odkaz níže.",
|
||||
"codeExpiry": "Platnost kódu vyprší {date} v {time} UTC, což je za {expiresInMinutes}.",
|
||||
"pin": "PIN"
|
||||
},
|
||||
"userDeleted": {
|
||||
"name": "Smazání uživatele",
|
||||
"title": "Váš účet byl smazán - Jellyfin",
|
||||
"yourAccountWasDeleted": "Váš účet Jellyfin byl smazán."
|
||||
},
|
||||
"userDisabled": {
|
||||
"name": "Uživatel zakázán",
|
||||
"title": "Váš účet byl deaktivován - Jellyfin",
|
||||
"yourAccountWasDisabled": "Váš účet byl deaktivován."
|
||||
},
|
||||
"userEnabled": {
|
||||
"name": "Uživatel povolen",
|
||||
"title": "Váš účet byl znovu aktivován - Jellyfin",
|
||||
"yourAccountWasEnabled": "Váš účet byl znovu aktivován."
|
||||
},
|
||||
"inviteEmail": {
|
||||
"name": "Pozvací e-mail",
|
||||
"title": "Pozvat - Jellyfin",
|
||||
"hello": "Ahoj",
|
||||
"youHaveBeenInvited": "Byli jste pozváni do Jellyfinu.",
|
||||
"toJoin": "Chcete-li se připojit, postupujte podle níže uvedeného odkazu.",
|
||||
"inviteExpiry": "Platnost této pozvánky vyprší {date} v {time}, což je za {expiresInMinutes}, proto jednejte rychle.",
|
||||
"linkButton": "Nastavte si účet"
|
||||
},
|
||||
"welcomeEmail": {
|
||||
"name": "Vítejte",
|
||||
"title": "Vítejte v Jellyfin",
|
||||
"welcome": "Vítejte v Jellyfin!",
|
||||
"youCanLoginWith": "Přihlásit se můžete pomocí níže uvedených údajů",
|
||||
"yourAccountWillExpire": "Platnost vašeho účtu vyprší dne {date}.",
|
||||
"jellyfinURL": "URL"
|
||||
},
|
||||
"emailConfirmation": {
|
||||
"name": "Potvrzující email",
|
||||
"title": "Potvrďte svůj email - Jellyfin",
|
||||
"clickBelow": "Kliknutím na odkaz níže potvrďte svou e-mailovou adresu a začněte používat Jellyfin.",
|
||||
"confirmEmail": "Potvrdit email"
|
||||
},
|
||||
"userExpired": {
|
||||
"name": "Vypršení platnosti uživatele",
|
||||
"title": "Platnost vašeho účtu vypršela – Jellyfin",
|
||||
"yourAccountHasExpired": "Platnost vašeho účtu vypršela.",
|
||||
"contactTheAdmin": "Pro více informací kontaktujte administrátora."
|
||||
}
|
||||
}
|
82
lang/form/cs-cz.json
Normal file
82
lang/form/cs-cz.json
Normal file
@ -0,0 +1,82 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Čeština (CZ)"
|
||||
},
|
||||
"strings": {
|
||||
"pageTitle": "Vytvořte účet Jellyfin",
|
||||
"createAccountHeader": "Vytvořit účet",
|
||||
"accountDetails": "Podrobnosti",
|
||||
"emailAddress": "Email",
|
||||
"username": "Uživatelské jméno",
|
||||
"oldPassword": "Staré heslo",
|
||||
"newPassword": "Nové heslo",
|
||||
"password": "Heslo",
|
||||
"reEnterPassword": "Znovu zadejte heslo",
|
||||
"reEnterPasswordInvalid": "Hesla nejsou stejná.",
|
||||
"createAccountButton": "Vytvořit účet",
|
||||
"passwordRequirementsHeader": "Požadavky na heslo",
|
||||
"successHeader": "Hotovo!",
|
||||
"confirmationRequired": "Vyžaduje se potvrzení e-mailem",
|
||||
"confirmationRequiredMessage": "Zkontrolujte prosím svou e-mailovou schránku a ověřte svou adresu.",
|
||||
"yourAccountIsValidUntil": "Váš účet bude platný do {date}.",
|
||||
"sendPIN": "Odešlete robotovi níže uvedený PIN a poté se sem vraťte a propojte svůj účet.",
|
||||
"sendPINDiscord": "Napište {command} do {server_channel} na Discordu a poté odešlete PIN níže.",
|
||||
"matrixEnterUser": "Zadejte své uživatelské ID, stiskněte Odeslat a bude vám zaslán PIN. Chcete-li pokračovat, zadejte jej zde.",
|
||||
"welcomeUser": "Vítejte, {user}!",
|
||||
"addContactMethod": "Přidat metodu kontaktu",
|
||||
"editContactMethod": "Upravit metodu kontaktu",
|
||||
"joinTheServer": "Připojte se na server:",
|
||||
"customMessagePlaceholderHeader": "Přizpůsobte si tuto kartu",
|
||||
"customMessagePlaceholderContent": "Kliknutím na tlačítko upravit stránku uživatele v nastavení můžete přizpůsobit tuto kartu nebo ji zobrazit na přihlašovací obrazovce a nebojte se, uživatel to nevidí.",
|
||||
"userPageSuccessMessage": "Podrobnosti o svém účtu můžete později zobrazit a změnit na stránce {myAccount}.",
|
||||
"resetPassword": "Obnovit heslo",
|
||||
"resetPasswordThroughJellyfin": "Chcete-li obnovit heslo, navštivte {jfLink} a stiskněte tlačítko \"Zapomenuté heslo\".",
|
||||
"resetPasswordThroughLink": "Chcete-li obnovit heslo, zadejte své uživatelské jméno, e-mailovou adresu nebo uživatelské jméno propojené kontaktní metody a odešlete. Bude odeslán odkaz pro resetování hesla.",
|
||||
"resetSent": "Resetování odesláno.",
|
||||
"resetSentDescription": "Pokud existuje účet s daným uživatelským jménem/způsobem kontaktu, byl prostřednictvím všech dostupných způsobů kontaktu odeslán odkaz pro resetování hesla. Platnost kódu vyprší za 30 minut.",
|
||||
"changePassword": "Změnit heslo",
|
||||
"referralsDescription": "Pozvěte přátele a rodinu do Jellyfin pomocí tohoto odkazu. Vraťte se sem pro nový, pokud vyprší.",
|
||||
"copyReferral": "Kopírovat odkaz",
|
||||
"invitedBy": "Pozval vás uživatel {user}."
|
||||
},
|
||||
"notifications": {
|
||||
"errorUserExists": "Uživatel již existuje.",
|
||||
"errorInvalidCode": "Neplatný zvací kód.",
|
||||
"errorAccountLinked": "Účet se již používá.",
|
||||
"errorEmailLinked": "Email je již používán.",
|
||||
"errorTelegramVerification": "Je vyžadováno ověření telegramem.",
|
||||
"errorDiscordVerification": "Vyžaduje se ověření neshody.",
|
||||
"errorMatrixVerification": "Vyžaduje se ověření matice.",
|
||||
"errorInvalidPIN": "PIN je neplatný.",
|
||||
"errorUnknown": "Neznámá chyba.",
|
||||
"errorNoEmail": "Email je vyžadován.",
|
||||
"errorCaptcha": "Captcha je nesprávná.",
|
||||
"errorPassword": "Zkontrolujte požadavky na heslo.",
|
||||
"errorNoMatch": "Hesla se neshodují.",
|
||||
"errorOldPassword": "Staré heslo je nesprávné.",
|
||||
"passwordChanged": "Heslo změněno.",
|
||||
"verified": "Účet ověřen."
|
||||
},
|
||||
"validationStrings": {
|
||||
"length": {
|
||||
"singular": "Musí mít alespoň {n} znak",
|
||||
"plural": "Musí mít nejméně {n} znaků"
|
||||
},
|
||||
"uppercase": {
|
||||
"singular": "Musí mít alespoň {n} velkých písmen",
|
||||
"plural": "Musí obsahovat alespoň {n} velkých písmen"
|
||||
},
|
||||
"lowercase": {
|
||||
"singular": "Musí mít alespoň {n} malých písmen",
|
||||
"plural": "Musí obsahovat alespoň {n} malých písmen"
|
||||
},
|
||||
"number": {
|
||||
"singular": "Musí mít alespoň {n} číslo",
|
||||
"plural": "Musí mít alespoň {n} čísel"
|
||||
},
|
||||
"special": {
|
||||
"singular": "Musí mít alespoň {n} speciálních znaků",
|
||||
"plural": "Musí obsahovat alespoň {n} speciálních znaků"
|
||||
}
|
||||
}
|
||||
}
|
16
lang/pwreset/cs-cz.json
Normal file
16
lang/pwreset/cs-cz.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Čeština (CZ)"
|
||||
},
|
||||
"strings": {
|
||||
"passwordReset": "Resetovat heslo",
|
||||
"reset": "Resetovat",
|
||||
"resetFailed": "Obnovení hesla se nezdařilo",
|
||||
"tryAgain": "Prosím zkuste to znovu.",
|
||||
"youCanLogin": "Nyní se můžete přihlásit pomocí níže uvedeného kódu jako svého hesla.",
|
||||
"youCanLoginOmbi": "Nyní se můžete přihlásit do Jellyfin & Ombi pomocí níže uvedeného kódu jako hesla.",
|
||||
"youCanLoginPassword": "Nyní se můžete přihlásit pomocí svého nového hesla. Stisknutím níže pokračujte na Jellyfin.",
|
||||
"changeYourPassword": "Po přihlášení nezapomeňte změnit heslo.",
|
||||
"enterYourPassword": "Níže zadejte své nové heslo."
|
||||
}
|
||||
}
|
160
lang/setup/cs-cz.json
Normal file
160
lang/setup/cs-cz.json
Normal file
@ -0,0 +1,160 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Čeština (CZ)"
|
||||
},
|
||||
"strings": {
|
||||
"pageTitle": "Nastavení - jfa-go",
|
||||
"next": "Další",
|
||||
"back": "Zpět",
|
||||
"optional": "Volitelný",
|
||||
"serverType": "Typ serveru",
|
||||
"disabled": "Zakázáno",
|
||||
"enabled": "Povoleno",
|
||||
"port": "Port",
|
||||
"message": "Zpráva",
|
||||
"serverAddress": "Adresa serveru",
|
||||
"emailSubject": "Předmět emailu",
|
||||
"URL": "URL",
|
||||
"apiKey": "Klíč API",
|
||||
"error": "Chyba",
|
||||
"errorInvalidUserPass": "Neplatné uživatelské jméno či heslo.",
|
||||
"errorNotAdmin": "Uživatel nemá oprávnění spravovat server.",
|
||||
"errorUserDisabled": "Uživatel může být zakázán.",
|
||||
"error404": "404, zkontrolujte interní URL.",
|
||||
"errorConnectionRefused": "Spojení odmítnuto.",
|
||||
"errorUnknown": "Neznámá chyba, zkontrolujte protokoly aplikace."
|
||||
},
|
||||
"startPage": {
|
||||
"welcome": "Vítejte!",
|
||||
"pressStart": "Chcete-li nastavit jfa-go, budete muset udělat několik věcí. Pokračujte stisknutím tlačítka start.",
|
||||
"httpsNotice": "Ujistěte se, že na tuto stránku přistupujete přes HTTPS nebo v privátní síti.",
|
||||
"start": "Start"
|
||||
},
|
||||
"endPage": {
|
||||
"finished": "Ukončeno!",
|
||||
"restartMessage": "Funkce jako roboti Discord/Telegram/Matrix, vlastní zprávy Markdown a uživatelsky přístupná stránka \"Můj účet\" najdete v Nastavení, takže si ji nezapomeňte prohlédnout. Kliknutím níže restartujte a poté obnovte stránku.",
|
||||
"refreshPage": "Obnovit"
|
||||
},
|
||||
"language": {
|
||||
"title": "Jazyk",
|
||||
"description": "Komunitní překlady jsou k dispozici pro většinu částí jfa-go. Níže si můžete vybrat výchozí jazyky, ale uživatelé je stále mohou změnit, pokud si to přejí. Pokud chcete pomoci s překladem, přihlaste se k {n} a začněte přispívat!",
|
||||
"defaultAdminLang": "Výchozí jazyk správce",
|
||||
"defaultFormLang": "Výchozí jazyk vytváření účtu",
|
||||
"defaultEmailLang": "Výchozí jazyk e-mailu"
|
||||
},
|
||||
"general": {
|
||||
"title": "Všeobecné",
|
||||
"listenAddress": "Posloucha adresu",
|
||||
"urlBase": "URL Base",
|
||||
"urlBaseNotice": "Je potřeba pouze při použití reverzního proxy na subdoméně (např. 'jellyf.in/accounts').",
|
||||
"lightTheme": "Světlý",
|
||||
"darkTheme": "Tmavý",
|
||||
"useHTTPS": "Použijte HTTPS",
|
||||
"httpsPort": "HTTPS Port",
|
||||
"useHTTPSNotice": "Doporučeno pouze v případě, že nepoužíváte reverzní proxy.",
|
||||
"pathToCertificate": "Cesta k certifikátu",
|
||||
"pathToKeyFile": "Cesta k souboru klíče"
|
||||
},
|
||||
"updates": {
|
||||
"title": "Aktualizace",
|
||||
"description": "Povolte, abyste byli informováni, když jsou k dispozici nové aktualizace. jfa-go bude kontrolovat {n} každých 30 minut. Nejsou shromažďovány žádné IP adresy ani osobní údaje.",
|
||||
"updateChannel": "Aktualizovat kanál",
|
||||
"stable": "Stabilní",
|
||||
"unstable": "Nestabilní"
|
||||
},
|
||||
"login": {
|
||||
"title": "Přihlásit se",
|
||||
"description": "Pro přístup na stránku správce se musíte přihlásit níže uvedeným způsobem:",
|
||||
"authorizeWithJellyfin": "Autorizovat pomocí Jellyfin/Emby: Přihlašovací údaje jsou sdíleny s Jellyfinem, což umožňuje více uživatelů.",
|
||||
"authorizeManual": "Uživatelské jméno a heslo: Ručně nastavte uživatelské jméno a heslo.",
|
||||
"adminOnly": "Pouze správci (doporučeno)",
|
||||
"allowAll": "Povolit všem uživatelům Jellyfin přihlášení",
|
||||
"allowAllDescription": "Nedoporučuje se, měli byste povolit přihlášení jednotlivých uživatelů po nastavení.",
|
||||
"authorizeManualUserPageNotice": "Pomocí tohoto deaktivujete funkci \"Uživatelská stránka\".",
|
||||
"emailNotice": "Vaši e-mailovou adresu lze použít k přijímání upozornění."
|
||||
},
|
||||
"jellyfinEmby": {
|
||||
"title": "Jellyfin/Emby",
|
||||
"description": "Účet správce je nutný, protože rozhraní API neumožňuje vytváření uživatelů pomocí klíče API. Měli byste si vytvořit samostatný účet a zaškrtnout 'Povolit tomuto uživateli spravovat server'. Vše ostatní můžete zakázat. Až budete hotovi, zadejte zde přihlašovací údaje.",
|
||||
"embyNotice": "Podpora Emby je omezená a nepodporuje resetování hesla.",
|
||||
"internal": "Vnitřní",
|
||||
"external": "Externí",
|
||||
"replaceJellyfin": "Název serveru",
|
||||
"replaceJellyfinNotice": "Pokud je uveden, nahradí to jakýkoli výskyt 'Jellyfin' v aplikaci.",
|
||||
"addressExternalNotice": "Chcete-li použít stejnou adresu, ponechte prázdné.",
|
||||
"testConnection": "Test připojení"
|
||||
},
|
||||
"ombi": {
|
||||
"title": "Ombi",
|
||||
"description": "Připojením k Ombi se vytvoří účet Jellyfin i Ombi, když se uživatel připojí přes jfa-go. Po dokončení nastavení přejděte do Nastavení a nastavte výchozí profil pro nové uživatele ombi.",
|
||||
"apiKeyNotice": "Najdete to na první kartě nastavení Ombi."
|
||||
},
|
||||
"messages": {
|
||||
"title": "Zprávy",
|
||||
"description": "jfa-go může odesílat resetování hesla a různé zprávy prostřednictvím e-mailu, Discordu, telegramu a/nebo Matrixu. Níže si můžete nastavit e-mail a ostatní můžete nakonfigurovat v Nastavení později. Pokyny naleznete na {n}. Pokud to nepotřebujete, můžete zde tyto funkce zakázat."
|
||||
},
|
||||
"email": {
|
||||
"title": "Email",
|
||||
"description": "jfa-go může posílat PINy pro resetování hesla a různá upozornění prostřednictvím e-mailu. Můžete se připojit k serveru SMTP nebo použít {n} API.",
|
||||
"method": "Způsob odeslání",
|
||||
"useEmailAsUsername": "Jako uživatelské jméno použijte e-mailové adresy",
|
||||
"useEmailAsUsernameNotice": "Pokud je povoleno, noví uživatelé se budou přihlašovat do Jellyfin/Emby pomocí své e-mailové adresy namísto uživatelského jména.",
|
||||
"fromAddress": "Z adresy",
|
||||
"senderName": "Jméno odesílatele",
|
||||
"dateFormat": "Datový formát",
|
||||
"dateFormatNotice": "Datum má formát strftime. Pro více informací navštivte {n}.",
|
||||
"encryption": "Šifrování",
|
||||
"mailgunApiURL": "API URL"
|
||||
},
|
||||
"notifications": {
|
||||
"title": "Upozornění pro správce",
|
||||
"description": "Je-li povoleno, můžete si vybrat (na pozvánku), že chcete dostávat zprávu, když pozvánka vyprší nebo když je vytvořen uživatel. Pokud jste nezvolili způsob přihlášení Jellyfin, ujistěte se, že jste uvedli svou e-mailovou adresu, nebo později přidejte jiný způsob kontaktu."
|
||||
},
|
||||
"userPage": {
|
||||
"title": "Uživatelská stránka",
|
||||
"description": "Uživatelská stránka (zobrazená jako \"Můj účet\") umožňuje uživatelům přístup k informacím o jejich účtu, jako jsou jejich způsoby kontaktu a vypršení platnosti účtu. Mohou si také změnit heslo, zahájit resetování hesla a propojit/změnit způsoby kontaktu, aniž by se vás museli ptát. Kromě toho mohou být uživatelům před a po přihlášení zobrazeny přizpůsobené zprávy Markdown.",
|
||||
"customizeMessages": "Chcete-li je nastavit později, klikněte v nastavení na tlačítko Upravit vedle položky \"Stránka uživatele\".",
|
||||
"requiredSettings": "Musí být nastaveno přihlášení do jfa-go přes Jellyfin. Zajistěte, aby bylo později pro samoobslužné resetování hesla vybráno \"resetovat heslo přes odkaz\"."
|
||||
},
|
||||
"welcomeEmails": {
|
||||
"title": "Uvítací zprávy",
|
||||
"description": "Pokud je povoleno, bude novým uživatelům odeslána zpráva s adresou URL Jellyfin/Emby a jejich uživatelským jménem."
|
||||
},
|
||||
"inviteEmails": {
|
||||
"title": "Pozvací zprávy",
|
||||
"description": "Pokud je povoleno, můžete posílat pozvánky přímo na e-mailovou adresu uživatele, uživatele Discordu nebo Matrixu. Protože možná používáte reverzní proxy, musíte zadat adresy URL, ze kterých se přistupuje k pozvánkám. Napište základ URL a připojte '/invite'."
|
||||
},
|
||||
"passwordResets": {
|
||||
"title": "Obnovení hesla",
|
||||
"description": "Když se uživatel pokusí resetovat své heslo, Jellyfin vytvoří soubor s názvem 'passwordreset-*.json', který obsahuje PIN. jfa-go přečte soubor a odešle PIN uživateli. Pokud jste povolili funkci \"Uživatelská stránka\", lze reset provést také tam, zadáte-li uživatelské jméno, e-mail nebo způsob kontaktu.",
|
||||
"pathToJellyfin": "Cesta ke konfiguračnímu adresáři Jellyfin",
|
||||
"pathToJellyfinNotice": "Pokud nevíte, kde to je, zkuste resetovat heslo v Jellyfin. Objeví se vyskakovací okno s '<cesta k jellyfin>/passwordreset-*.json'. Toto není nutné, pokud chcete používat pouze samoobslužné resetování hesla prostřednictvím \"Uživatelské stránky\".",
|
||||
"resetLinks": "Místo PINu pošlete odkaz",
|
||||
"resetLinksRequiredForUserPage": "Vyžadováno pro samoobslužné resetování hesla na Uživatelské stránce.",
|
||||
"resetLinksNotice": "Pokud je povolena integrace Ombi, použijte tuto možnost k synchronizaci resetování hesla Jellyfin s Ombi.",
|
||||
"resetLinksLanguage": "Výchozí odkaz k resetování jazyku",
|
||||
"setPassword": "Nastavit heslo přes odkaz",
|
||||
"setPasswordNotice": "Povolení znamená, že uživatel nemusí po resetování měnit své heslo z PIN. Bude také vynuceno ověření hesla."
|
||||
},
|
||||
"passwordValidation": {
|
||||
"title": "Ověření hesla",
|
||||
"description": "Pokud je povoleno, na stránce vytvoření účtu se zobrazí sada požadavků na heslo, jako je minimální délka, velká/malá písmena atd.",
|
||||
"length": "Délka",
|
||||
"uppercase": "Velká písmena",
|
||||
"lowercase": "Malá písmena",
|
||||
"numbers": "Čísla",
|
||||
"special": "Speciální znaky (%, * atd.)"
|
||||
},
|
||||
"helpMessages": {
|
||||
"title": "Zprávy nápovědy",
|
||||
"description": "Tyto zprávy se zobrazí na stránce vytvoření účtu a v některých e-mailech.",
|
||||
"contactMessage": "Kontaktní zpráva",
|
||||
"contactMessageNotice": "Zobrazí se v dolní části všech stránek kromě admin.",
|
||||
"helpMessage": "Zpráva nápovědy",
|
||||
"helpMessageNotice": "Zobrazí se na stránce vytvoření účtu.",
|
||||
"successMessage": "Zpráva o úspěchu",
|
||||
"successMessageNotice": "Zobrazí se, když si uživatel vytvoří svůj účet.",
|
||||
"emailMessage": "Emailová zpráva",
|
||||
"emailMessageNotice": "Zobrazuje se ve spodní části e-mailů."
|
||||
}
|
||||
}
|
@ -18,11 +18,12 @@
|
||||
"apiKey": "API Key",
|
||||
"error": "Error",
|
||||
"errorInvalidUserPass": "Invalid username/password.",
|
||||
"errorNotAdmin": "User is not allowed to manage server.",
|
||||
"errorNotAdmin": "User is not aEnabledllowed to manage server.",
|
||||
"errorUserDisabled": "User may be disabled.",
|
||||
"error404": "404, check the internal URL.",
|
||||
"errorConnectionRefused": "Connection refused.",
|
||||
"errorUnknown": "Unknown error, check app logs."
|
||||
"errorUnknown": "Unknown error, check app logs.",
|
||||
"errorProxy": "Proxy configuration invalid."
|
||||
},
|
||||
"startPage": {
|
||||
"welcome": "Welcome!",
|
||||
@ -62,6 +63,12 @@
|
||||
"stable": "Stable",
|
||||
"unstable": "Unstable"
|
||||
},
|
||||
"proxy": {
|
||||
"title": "Proxy",
|
||||
"description": "Have jfa-go make all connections through a HTTP/SOCKS5 proxy. Connection to Jellyfin will be tested through this.",
|
||||
"protocol": "Protocol",
|
||||
"address": "Address (Including Port)"
|
||||
},
|
||||
"login": {
|
||||
"title": "Login",
|
||||
"description": "To access the admin page, you need to login with a method below:",
|
||||
|
16
lang/telegram/cs-cz.json
Normal file
16
lang/telegram/cs-cz.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "Čeština (CZ)"
|
||||
},
|
||||
"strings": {
|
||||
"startMessage": "Ahoj!\nZde zadejte svůj PIN kód Jellyfin pro ověření svého účtu.",
|
||||
"discordStartMessage": "Ahoj!\n Zadejte svůj PIN pomocí `/pin <PIN>` pro ověření svého účtu.",
|
||||
"matrixStartMessage": "Ahoj\nZadejte níže uvedený PIN na přihlašovací stránce Jellyfin a ověřte svůj účet.",
|
||||
"invalidPIN": "Tento PIN byl neplatný, zkuste to znovu.",
|
||||
"pinSuccess": "Hotovo! Nyní se můžete vrátit na stránku registrace.",
|
||||
"languageMessage": "Poznámka: Dostupné jazyky zobrazíte pomocí příkazu {command} a jazyk nastavíte pomocí příkazu {command} <kód jazyka>.",
|
||||
"languageMessageDiscord": "Poznámka: nastavte svůj jazyk pomocí /lang <název jazyka>.",
|
||||
"languageSet": "Jazyk nastaven na {language}.",
|
||||
"discordDMs": "Zkontrolujte prosím své DM pro odpověď."
|
||||
}
|
||||
}
|
12
package-lock.json
generated
12
package-lock.json
generated
@ -6677,9 +6677,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/word-wrap": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
||||
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz",
|
||||
"integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@ -11812,9 +11812,9 @@
|
||||
}
|
||||
},
|
||||
"word-wrap": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
||||
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ=="
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz",
|
||||
"integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA=="
|
||||
},
|
||||
"wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
|
36
setup.go
36
setup.go
@ -7,6 +7,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/hrfee/jfa-go/easyproxy"
|
||||
"github.com/hrfee/mediabrowser"
|
||||
)
|
||||
|
||||
@ -47,10 +48,15 @@ func (app *appContext) ServeSetup(gc *gin.Context) {
|
||||
}
|
||||
|
||||
type testReq struct {
|
||||
ServerType string `json:"type"`
|
||||
Server string `json:"server"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
ServerType string `json:"type"`
|
||||
Server string `json:"server"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Proxy bool `json:"proxy"`
|
||||
ProxyProtocol string `json:"proxy_protocol,omitempty"`
|
||||
ProxyAddress string `json:"proxy_address,omitempty"`
|
||||
ProxyUsername string `json:"proxy_user,omitempty"`
|
||||
ProxyPassword string `json:"proxy_password,omitempty"`
|
||||
}
|
||||
|
||||
func (app *appContext) TestJF(gc *gin.Context) {
|
||||
@ -64,6 +70,26 @@ func (app *appContext) TestJF(gc *gin.Context) {
|
||||
serverType = mediabrowser.EmbyServer
|
||||
}
|
||||
tempjf, _ := mediabrowser.NewServer(serverType, req.Server, "jfa-go-setup", app.version, "auth", "auth", mediabrowser.NewNamedTimeoutHandler("authJF", req.Server, true), 30)
|
||||
|
||||
if req.Proxy {
|
||||
conf := easyproxy.ProxyConfig{
|
||||
Protocol: easyproxy.HTTP,
|
||||
Addr: req.ProxyAddress,
|
||||
User: req.ProxyUsername,
|
||||
Password: req.ProxyPassword,
|
||||
}
|
||||
if strings.Contains(req.ProxyProtocol, "socks") {
|
||||
conf.Protocol = easyproxy.SOCKS5
|
||||
}
|
||||
|
||||
transport, err := easyproxy.NewTransport(conf)
|
||||
if err != nil {
|
||||
respond(400, "errorProxy", gc)
|
||||
return
|
||||
}
|
||||
tempjf.SetTransport(transport)
|
||||
}
|
||||
|
||||
user, status, err := tempjf.Authenticate(req.Username, req.Password)
|
||||
if !(status == 200 || status == 204) || err != nil {
|
||||
msg := ""
|
||||
@ -126,6 +152,7 @@ func (st *Storage) loadLangSetup(filesystems ...fs.FS) error {
|
||||
patchLang(&lang.Strings, &fallback.Strings, &english.Strings)
|
||||
patchLang(&lang.StartPage, &fallback.StartPage, &english.StartPage)
|
||||
patchLang(&lang.Updates, &fallback.Updates, &english.Updates)
|
||||
patchLang(&lang.Proxy, &fallback.Proxy, &english.Proxy)
|
||||
patchLang(&lang.EndPage, &fallback.EndPage, &english.EndPage)
|
||||
patchLang(&lang.Language, &fallback.Language, &english.Language)
|
||||
patchLang(&lang.Login, &fallback.Login, &english.Login)
|
||||
@ -144,6 +171,7 @@ func (st *Storage) loadLangSetup(filesystems ...fs.FS) error {
|
||||
patchLang(&lang.Strings, &english.Strings)
|
||||
patchLang(&lang.StartPage, &english.StartPage)
|
||||
patchLang(&lang.Updates, &english.Updates)
|
||||
patchLang(&lang.Proxy, &english.Proxy)
|
||||
patchLang(&lang.EndPage, &english.EndPage)
|
||||
patchLang(&lang.Language, &english.Language)
|
||||
patchLang(&lang.Login, &english.Login)
|
||||
|
@ -946,6 +946,8 @@ export class accountsList {
|
||||
}
|
||||
}
|
||||
|
||||
private _notFoundPanel: HTMLElement = document.getElementById("accounts-not-found");
|
||||
|
||||
search = (query: String): string[] => {
|
||||
console.log(this._queries);
|
||||
this._filterArea.textContent = "";
|
||||
@ -2021,17 +2023,25 @@ export class accountsList {
|
||||
this._inSearch = true;
|
||||
// this.setVisibility(this.search(query), true);
|
||||
}
|
||||
this.setVisibility(this.search(query), true);
|
||||
const results = this.search(query);
|
||||
this.setVisibility(results, true);
|
||||
this._checkCheckCount();
|
||||
this.showHideSearchOptionsHeader();
|
||||
if (results.length == 0) {
|
||||
this._notFoundPanel.classList.remove("unfocused");
|
||||
} else {
|
||||
this._notFoundPanel.classList.add("unfocused");
|
||||
}
|
||||
};
|
||||
this._search.oninput = onchange;
|
||||
|
||||
const clearSearchButton = document.getElementById("accounts-search-clear") as HTMLSpanElement;
|
||||
clearSearchButton.addEventListener("click", () => {
|
||||
this._search.value = "";
|
||||
onchange();
|
||||
});
|
||||
const clearSearchButtons = Array.from(document.getElementsByClassName("accounts-search-clear")) as Array<HTMLSpanElement>;
|
||||
for (let b of clearSearchButtons) {
|
||||
b.addEventListener("click", () => {
|
||||
this._search.value = "";
|
||||
onchange();
|
||||
});
|
||||
}
|
||||
|
||||
this._announceTextarea.onkeyup = this.loadPreview;
|
||||
addDiscord = newDiscordSearch(window.lang.strings("linkDiscord"), window.lang.strings("searchDiscordUser"), window.lang.strings("add"), (user: DiscordUser, id: string) => {
|
||||
@ -2084,8 +2094,15 @@ export class accountsList {
|
||||
// console.log("ordering by", event.detail, ": ", this._ordering);
|
||||
if (!(this._inSearch)) {
|
||||
this.setVisibility(this._ordering, true);
|
||||
this._notFoundPanel.classList.add("unfocused");
|
||||
} else {
|
||||
this.setVisibility(this.search(this._search.value), true);
|
||||
const results = this.search(this._search.value);
|
||||
this.setVisibility(results, true);
|
||||
if (results.length == 0) {
|
||||
this._notFoundPanel.classList.remove("unfocused");
|
||||
} else {
|
||||
this._notFoundPanel.classList.add("unfocused");
|
||||
}
|
||||
}
|
||||
this.showHideSearchOptionsHeader();
|
||||
});
|
||||
@ -2195,8 +2212,15 @@ export class accountsList {
|
||||
this._ordering = this._columns[this._activeSortColumn].sort(this._users);
|
||||
if (!(this._inSearch)) {
|
||||
this.setVisibility(this._ordering, true);
|
||||
this._notFoundPanel.classList.add("unfocused");
|
||||
} else {
|
||||
this.setVisibility(this.search(this._search.value), true);
|
||||
const results = this.search(this._search.value);
|
||||
if (results.length == 0) {
|
||||
this._notFoundPanel.classList.remove("unfocused");
|
||||
} else {
|
||||
this._notFoundPanel.classList.add("unfocused");
|
||||
}
|
||||
this.setVisibility(results, true);
|
||||
}
|
||||
this._checkCheckCount();
|
||||
}
|
||||
|
@ -102,6 +102,7 @@ class DOMInput {
|
||||
constructor(inputType: string, setting: Setting, section: string, name: string) {
|
||||
this._container = document.createElement("div");
|
||||
this._container.classList.add("setting");
|
||||
this._container.setAttribute("data-name", name)
|
||||
this._container.innerHTML = `
|
||||
<label class="label">
|
||||
<span class="setting-label"></span> <span class="setting-required"></span> <span class="setting-restart"></span>
|
||||
@ -262,6 +263,7 @@ class DOMBool implements SBool {
|
||||
constructor(setting: SBool, section: string, name: string) {
|
||||
this._container = document.createElement("div");
|
||||
this._container.classList.add("setting");
|
||||
this._container.setAttribute("data-name", name)
|
||||
this._container.innerHTML = `
|
||||
<label class="switch mb-2">
|
||||
<input type="checkbox">
|
||||
@ -396,6 +398,7 @@ class DOMSelect implements SSelect {
|
||||
this._options = [];
|
||||
this._container = document.createElement("div");
|
||||
this._container.classList.add("setting");
|
||||
this._container.setAttribute("data-name", name)
|
||||
this._container.innerHTML = `
|
||||
<label class="label">
|
||||
<span class="setting-label"></span> <span class="setting-required"></span> <span class="setting-restart"></span>
|
||||
@ -544,9 +547,10 @@ class sectionPanel {
|
||||
this._settings = {};
|
||||
this._section = document.createElement("div") as HTMLDivElement;
|
||||
this._section.classList.add("settings-section", "unfocused");
|
||||
this._section.setAttribute("data-section", sectionName);
|
||||
this._section.innerHTML = `
|
||||
<span class="heading">${s.meta.name}</span>
|
||||
<p class="support lg my-2">${s.meta.description}</p>
|
||||
<p class="support lg my-2 settings-section-description">${s.meta.description}</p>
|
||||
`;
|
||||
|
||||
this.update(s);
|
||||
@ -618,10 +622,19 @@ export class settingsList {
|
||||
|
||||
private _panel = document.getElementById("settings-panel") as HTMLDivElement;
|
||||
private _sidebar = document.getElementById("settings-sidebar") as HTMLDivElement;
|
||||
private _visibleSection: string;
|
||||
private _sections: { [name: string]: sectionPanel }
|
||||
private _buttons: { [name: string]: HTMLSpanElement }
|
||||
private _needsRestart: boolean = false;
|
||||
private _messageEditor = new MessageEditor();
|
||||
private _settings: Settings;
|
||||
private _advanced: boolean = false;
|
||||
|
||||
private _searchbox: HTMLInputElement = document.getElementById("settings-search") as HTMLInputElement;
|
||||
private _clearSearchboxButtons: Array<HTMLButtonElement> = Array.from(document.getElementsByClassName("settings-search-clear")) as Array<HTMLButtonElement>;
|
||||
|
||||
private _noResultsPanel: HTMLElement = document.getElementById("settings-not-found");
|
||||
|
||||
|
||||
addSection = (name: string, s: Section, subButton?: HTMLElement) => {
|
||||
const section = new sectionPanel(s, name);
|
||||
@ -637,6 +650,7 @@ export class settingsList {
|
||||
let state = true;
|
||||
if (s.meta.depends_false) { state = false; }
|
||||
document.addEventListener(`settings-${dependant[0]}-${dependant[1]}`, (event: settingsBoolEvent) => {
|
||||
|
||||
if (Boolean(event.detail) !== state) {
|
||||
button.classList.add("unfocused");
|
||||
document.dispatchEvent(new CustomEvent(`settings-${name}`, { detail: false }));
|
||||
@ -659,6 +673,7 @@ export class settingsList {
|
||||
} else {
|
||||
button.classList.remove("unfocused");
|
||||
}
|
||||
this._searchbox.oninput(null);
|
||||
});
|
||||
}
|
||||
this._buttons[name] = button;
|
||||
@ -669,6 +684,7 @@ export class settingsList {
|
||||
for (let n in this._sections) {
|
||||
if (n == name) {
|
||||
this._sections[name].visible = true;
|
||||
this._visibleSection = name;
|
||||
this._buttons[name].classList.add("selected");
|
||||
} else {
|
||||
this._sections[n].visible = false;
|
||||
@ -736,15 +752,27 @@ export class settingsList {
|
||||
advancedEnableToggle.onchange = () => {
|
||||
document.dispatchEvent(new CustomEvent("settings-advancedState", { detail: advancedEnableToggle.checked }));
|
||||
const parent = advancedEnableToggle.parentElement;
|
||||
if (advancedEnableToggle.checked) {
|
||||
this._advanced = advancedEnableToggle.checked;
|
||||
if (this._advanced) {
|
||||
parent.classList.add("~urge");
|
||||
parent.classList.remove("~neutral");
|
||||
} else {
|
||||
parent.classList.add("~neutral");
|
||||
parent.classList.remove("~urge");
|
||||
}
|
||||
this._searchbox.oninput(null);
|
||||
};
|
||||
advancedEnableToggle.checked = false;
|
||||
|
||||
this._searchbox.oninput = () => {
|
||||
this.search(this._searchbox.value);
|
||||
};
|
||||
for (let b of this._clearSearchboxButtons) {
|
||||
b.onclick = () => {
|
||||
this._searchbox.value = "";
|
||||
this._searchbox.oninput(null);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
private _addMatrix = () => {
|
||||
@ -787,10 +815,10 @@ export class settingsList {
|
||||
window.notifications.customError("settingsLoadError", window.lang.notif("errorLoadSettings"));
|
||||
return;
|
||||
}
|
||||
let settings = req.response as Settings;
|
||||
for (let name of settings.order) {
|
||||
this._settings = req.response as Settings;
|
||||
for (let name of this._settings.order) {
|
||||
if (name in this._sections) {
|
||||
this._sections[name].update(settings.sections[name]);
|
||||
this._sections[name].update(this._settings.sections[name]);
|
||||
} else {
|
||||
if (name == "messages" || name == "user_page") {
|
||||
const editButton = document.createElement("div");
|
||||
@ -806,7 +834,7 @@ export class settingsList {
|
||||
(editButton.querySelector("span.button") as HTMLSpanElement).onclick = () => {
|
||||
this._messageEditor.showList(name == "messages" ? "email" : "user");
|
||||
};
|
||||
this.addSection(name, settings.sections[name], editButton);
|
||||
this.addSection(name, this._settings.sections[name], editButton);
|
||||
} else if (name == "updates") {
|
||||
const icon = document.createElement("span") as HTMLSpanElement;
|
||||
if (window.updater.updateAvailable) {
|
||||
@ -814,7 +842,7 @@ export class settingsList {
|
||||
icon.innerHTML = `<i class="ri-download-line" title="${window.lang.strings("update")}"></i>`;
|
||||
icon.onclick = () => window.updater.checkForUpdates(window.modals.updateInfo.show);
|
||||
}
|
||||
this.addSection(name, settings.sections[name], icon);
|
||||
this.addSection(name, this._settings.sections[name], icon);
|
||||
} else if (name == "matrix" && !window.matrixEnabled) {
|
||||
const addButton = document.createElement("div");
|
||||
addButton.classList.add("tooltip", "left");
|
||||
@ -825,19 +853,126 @@ export class settingsList {
|
||||
</span>
|
||||
`;
|
||||
(addButton.querySelector("span.button") as HTMLSpanElement).onclick = this._addMatrix;
|
||||
this.addSection(name, settings.sections[name], addButton);
|
||||
this.addSection(name, this._settings.sections[name], addButton);
|
||||
} else {
|
||||
this.addSection(name, settings.sections[name]);
|
||||
this.addSection(name, this._settings.sections[name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
this._showPanel(settings.order[0]);
|
||||
this._showPanel(this._settings.order[0]);
|
||||
document.dispatchEvent(new CustomEvent("settings-loaded"));
|
||||
document.dispatchEvent(new CustomEvent("settings-advancedState", { detail: false }));
|
||||
this._saveButton.classList.add("unfocused");
|
||||
this._needsRestart = false;
|
||||
}
|
||||
})
|
||||
|
||||
// FIXME: Search "About" & "User profiles", pseudo-search "User profiles" for things like "Ombi", "Referrals", etc.
|
||||
search = (query: string) => {
|
||||
query = query.toLowerCase().trim();
|
||||
// Make sure a blank search is detected when there's just whitespace.
|
||||
if (query.replace(/\s+/g, "") == "") query = "";
|
||||
|
||||
let firstVisibleSection = "";
|
||||
for (let section of this._settings.order) {
|
||||
|
||||
let dependencyCard = this._sections[section].asElement().querySelector(".settings-dependency-message");
|
||||
if (dependencyCard) dependencyCard.remove();
|
||||
dependencyCard = null;
|
||||
let dependencyList = null;
|
||||
|
||||
// hide button, unhide if matched
|
||||
this._buttons[section].classList.add("unfocused");
|
||||
|
||||
let matchedSection = false;
|
||||
|
||||
if (section.toLowerCase().includes(query) ||
|
||||
this._settings.sections[section].meta.name.toLowerCase().includes(query) ||
|
||||
this._settings.sections[section].meta.description.toLowerCase().includes(query)) {
|
||||
if ((this._settings.sections[section].meta.advanced && this._advanced) || !(this._settings.sections[section].meta.advanced)) {
|
||||
this._buttons[section].classList.remove("unfocused");
|
||||
firstVisibleSection = firstVisibleSection || section;
|
||||
matchedSection = true;
|
||||
}
|
||||
}
|
||||
const sectionElement = this._sections[section].asElement();
|
||||
for (let setting of this._settings.sections[section].order) {
|
||||
if (this._settings.sections[section].settings[setting].type == "note") continue;
|
||||
const element = sectionElement.querySelector(`div[data-name="${setting}"]`) as HTMLElement;
|
||||
|
||||
// If we match the whole section, don't bother searching settings.
|
||||
if (matchedSection) {
|
||||
element.classList.remove("opacity-50", "pointer-events-none");
|
||||
element.setAttribute("aria-disabled", "false");
|
||||
continue;
|
||||
}
|
||||
|
||||
// element.classList.remove("-mx-2", "my-2", "p-2", "aside", "~neutral", "@low");
|
||||
element.classList.add("opacity-50", "pointer-events-none");
|
||||
element.setAttribute("aria-disabled", "true");
|
||||
if (setting.toLowerCase().includes(query) ||
|
||||
this._settings.sections[section].settings[setting].name.toLowerCase().includes(query) ||
|
||||
this._settings.sections[section].settings[setting].description.toLowerCase().includes(query) ||
|
||||
String(this._settings.sections[section].settings[setting].value).toLowerCase().includes(query)) {
|
||||
if ((this._settings.sections[section].meta.advanced && this._advanced) || !(this._settings.sections[section].meta.advanced)) {
|
||||
this._buttons[section].classList.remove("unfocused");
|
||||
firstVisibleSection = firstVisibleSection || section;
|
||||
}
|
||||
const shouldShow = (query != "" &&
|
||||
((this._settings.sections[section].settings[setting].advanced && this._advanced) ||
|
||||
!(this._settings.sections[section].settings[setting].advanced)));
|
||||
if (shouldShow || query == "") {
|
||||
// element.classList.add("-mx-2", "my-2", "p-2", "aside", "~neutral", "@low");
|
||||
element.classList.remove("opacity-50", "pointer-events-none");
|
||||
element.setAttribute("aria-disabled", "false");
|
||||
}
|
||||
if (query != "" && ((shouldShow && element.querySelector("label").classList.contains("unfocused")) || (!shouldShow))) {
|
||||
// Add a note explaining why the setting is hidden
|
||||
if (!dependencyCard) {
|
||||
dependencyCard = document.createElement("aside");
|
||||
dependencyCard.classList.add("aside", "my-2", "~warning", "settings-dependency-message");
|
||||
dependencyCard.innerHTML = `
|
||||
<div class="content text-sm">
|
||||
<span class="font-bold">${window.lang.strings("settingsHiddenDependency")}</span>
|
||||
|
||||
<ul class="settings-dependency-list"></ul>
|
||||
</div>
|
||||
`;
|
||||
dependencyList = dependencyCard.querySelector(".settings-dependency-list") as HTMLUListElement;
|
||||
// Insert it right after the description
|
||||
this._sections[section].asElement().insertBefore(dependencyCard, this._sections[section].asElement().querySelector(".settings-section-description").nextElementSibling);
|
||||
}
|
||||
const li = document.createElement("li");
|
||||
if (shouldShow) {
|
||||
const depCode = this._settings.sections[section].settings[setting].depends_true || this._settings.sections[section].settings[setting].depends_false;
|
||||
const dep = splitDependant(section, depCode);
|
||||
|
||||
let depName = this._settings.sections[dep[0]].settings[dep[1]].name;
|
||||
if (dep[0] != section) {
|
||||
depName = this._settings.sections[dep[0]].meta.name + " > " + depName;
|
||||
}
|
||||
|
||||
li.textContent = window.lang.strings("settingsDependsOn").replace("{setting}", `"`+this._settings.sections[section].settings[setting].name+`"`).replace("{dependency}", `"`+depName+`"`);
|
||||
} else {
|
||||
li.textContent = window.lang.strings("settingsAdvancedMode").replace("{setting}", `"`+this._settings.sections[section].settings[setting].name+`"`);
|
||||
}
|
||||
dependencyList.appendChild(li);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (firstVisibleSection && (query != "" || this._visibleSection == "")) {
|
||||
this._buttons[firstVisibleSection].onclick(null);
|
||||
this._noResultsPanel.classList.add("unfocused");
|
||||
} else if (query != "") {
|
||||
this._noResultsPanel.classList.remove("unfocused");
|
||||
if (this._visibleSection) {
|
||||
this._sections[this._visibleSection].visible = false;
|
||||
this._buttons[this._visibleSection].classList.remove("selected");
|
||||
this._visibleSection = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface templateEmail {
|
||||
|
22
ts/setup.ts
22
ts/setup.ts
@ -85,6 +85,13 @@ class Checkbox {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (this._el.hasAttribute("checked")) {
|
||||
this._el.checked = true;
|
||||
} else {
|
||||
this._el.checked = false;
|
||||
}
|
||||
this.broadcast();
|
||||
}
|
||||
}
|
||||
|
||||
@ -315,10 +322,14 @@ const settings = {
|
||||
"tls": new Checkbox(get("advanced-tls"), "", false, "advanced", "tls"),
|
||||
"tls_port": new Input(get("advanced-tls_port"), "", "", "tls", true, "advanced"),
|
||||
"tls_cert": new Input(get("advanced-tls_cert"), "", "", "tls", true, "advanced"),
|
||||
"tls_key": new Input(get("advanced-tls_key"), "", "", "tls", true, "advanced")
|
||||
"tls_key": new Input(get("advanced-tls_key"), "", "", "tls", true, "advanced"),
|
||||
"proxy": new Checkbox(get("advanced-proxy"), "", false, "advanced", "proxy"),
|
||||
"proxy_protocol": new Select(get("advanced-proxy_protocol"), "proxy", true, "advanced"),
|
||||
"proxy_address": new Input(get("advanced-proxy_address"), "", "", "proxy", true, "advanced"),
|
||||
"proxy_user": new Input(get("advanced-proxy_user"), "", "", "proxy", true, "advanced"),
|
||||
"proxy_password": new Input(get("advanced-proxy_password"), "", "", "proxy", true, "advanced")
|
||||
}
|
||||
};
|
||||
|
||||
const checkTheme = () => {
|
||||
if (settings["ui"]["theme"].value.includes("Dark")) {
|
||||
document.documentElement.classList.add("dark-theme");
|
||||
@ -553,7 +564,12 @@ window.onpopstate = (event: PopStateEvent) => {
|
||||
"type": settings["jellyfin"]["type"].value,
|
||||
"server": settings["jellyfin"]["server"].value,
|
||||
"username": settings["jellyfin"]["username"].value,
|
||||
"password": settings["jellyfin"]["password"].value
|
||||
"password": settings["jellyfin"]["password"].value,
|
||||
"proxy": settings["advanced"]["proxy"].value == "true",
|
||||
"proxy_protocol": settings["advanced"]["proxy_protocol"].value,
|
||||
"proxy_address": settings["advanced"]["proxy_address"].value,
|
||||
"proxy_user": settings["advanced"]["proxy_user"].value,
|
||||
"proxy_password": settings["advanced"]["proxy_password"].value
|
||||
};
|
||||
_post("/jellyfin/test", send, (req: XMLHttpRequest) => {
|
||||
if (req.readyState == 4) {
|
||||
|
Loading…
Reference in New Issue
Block a user