mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-12-29 12:30:11 +00:00
Compare commits
6 Commits
fe62422a2a
...
75796a3981
Author | SHA1 | Date | |
---|---|---|---|
75796a3981 | |||
781047058f | |||
0ac61a59b2 | |||
732ed5b0b8 | |||
42ddbab6cf | |||
432d795880 |
3
.gitignore
vendored
3
.gitignore
vendored
@ -9,3 +9,6 @@ docs/*
|
|||||||
lang/langtostruct.py
|
lang/langtostruct.py
|
||||||
config-payload.json
|
config-payload.json
|
||||||
!docs/go.mod
|
!docs/go.mod
|
||||||
|
server.key
|
||||||
|
server.pem
|
||||||
|
server.crt
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#### Translation
|
#### Translation
|
||||||
Currently only the account creation form can be translated. Strings are defined in `lang/form/<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/form).
|
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.
|
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
|
#### Code
|
||||||
|
27
api.go
27
api.go
@ -1087,7 +1087,7 @@ func (app *appContext) GetConfig(gc *gin.Context) {
|
|||||||
// Load language options
|
// Load language options
|
||||||
loadLangs := func(langs *map[string]map[string]interface{}, settingsKey string) (string, []string) {
|
loadLangs := func(langs *map[string]map[string]interface{}, settingsKey string) (string, []string) {
|
||||||
langOptions := make([]string, len(*langs))
|
langOptions := make([]string, len(*langs))
|
||||||
chosenLang := app.config.Section("ui").Key("language-" + settingsKey).MustString("en-us")
|
chosenLang := app.config.Section("ui").Key("language" + settingsKey).MustString("en-us")
|
||||||
chosenLangName := (*langs)[chosenLang]["meta"].(map[string]interface{})["name"].(string)
|
chosenLangName := (*langs)[chosenLang]["meta"].(map[string]interface{})["name"].(string)
|
||||||
i := 0
|
i := 0
|
||||||
for _, lang := range *langs {
|
for _, lang := range *langs {
|
||||||
@ -1096,14 +1096,25 @@ func (app *appContext) GetConfig(gc *gin.Context) {
|
|||||||
}
|
}
|
||||||
return chosenLangName, langOptions
|
return chosenLangName, langOptions
|
||||||
}
|
}
|
||||||
formChosen, formOptions := loadLangs(&app.storage.lang.Form, "form")
|
formChosen, formOptions := loadLangs(&app.storage.lang.Form, "-form")
|
||||||
fl := resp.Sections["ui"].Settings["language-form"]
|
fl := resp.Sections["ui"].Settings["language-form"]
|
||||||
fl.Options = formOptions
|
fl.Options = formOptions
|
||||||
fl.Value = formChosen
|
fl.Value = formChosen
|
||||||
adminChosen, adminOptions := loadLangs(&app.storage.lang.Admin, "admin")
|
adminChosen, adminOptions := loadLangs(&app.storage.lang.Admin, "-admin")
|
||||||
al := resp.Sections["ui"].Settings["language-admin"]
|
al := resp.Sections["ui"].Settings["language-admin"]
|
||||||
al.Options = adminOptions
|
al.Options = adminOptions
|
||||||
al.Value = adminChosen
|
al.Value = adminChosen
|
||||||
|
emailOptions := make([]string, len(app.storage.lang.Email))
|
||||||
|
chosenLang := app.config.Section("email").Key("language").MustString("en-us")
|
||||||
|
emailChosen := app.storage.lang.Email.get(chosenLang, "meta", "name")
|
||||||
|
i := 0
|
||||||
|
for langName := range app.storage.lang.Email {
|
||||||
|
emailOptions[i] = app.storage.lang.Email.get(langName, "meta", "name")
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
el := resp.Sections["email"].Settings["language"]
|
||||||
|
el.Options = emailOptions
|
||||||
|
el.Value = emailChosen
|
||||||
for sectName, section := range resp.Sections {
|
for sectName, section := range resp.Sections {
|
||||||
for settingName, setting := range section.Settings {
|
for settingName, setting := range section.Settings {
|
||||||
val := app.config.Section(sectName).Key(settingName)
|
val := app.config.Section(sectName).Key(settingName)
|
||||||
@ -1121,10 +1132,11 @@ func (app *appContext) GetConfig(gc *gin.Context) {
|
|||||||
}
|
}
|
||||||
resp.Sections["ui"].Settings["language-form"] = fl
|
resp.Sections["ui"].Settings["language-form"] = fl
|
||||||
resp.Sections["ui"].Settings["language-admin"] = al
|
resp.Sections["ui"].Settings["language-admin"] = al
|
||||||
|
resp.Sections["email"].Settings["language"] = el
|
||||||
|
|
||||||
t := resp.Sections["jellyfin"].Settings["type"]
|
t := resp.Sections["jellyfin"].Settings["type"]
|
||||||
opts := make([]string, len(serverTypes))
|
opts := make([]string, len(serverTypes))
|
||||||
i := 0
|
i = 0
|
||||||
for _, v := range serverTypes {
|
for _, v := range serverTypes {
|
||||||
opts[i] = v
|
opts[i] = v
|
||||||
i++
|
i++
|
||||||
@ -1169,6 +1181,13 @@ func (app *appContext) ModifyConfig(gc *gin.Context) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if section == "email" && setting == "language" {
|
||||||
|
for key := range app.storage.lang.Email {
|
||||||
|
if app.storage.lang.Email.get(key, "meta", "name") == value.(string) {
|
||||||
|
tempConfig.Section("email").Key("language").SetValue(key)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if section == "jellyfin" && setting == "type" {
|
} else if section == "jellyfin" && setting == "type" {
|
||||||
for k, v := range serverTypes {
|
for k, v := range serverTypes {
|
||||||
if v == value.(string) {
|
if v == value.(string) {
|
||||||
|
@ -219,6 +219,50 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"advanced": {
|
||||||
|
"order": [],
|
||||||
|
"meta": {
|
||||||
|
"name": "Advanced",
|
||||||
|
"description": "Advanced settings."
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"tls": {
|
||||||
|
"name": "TLS/HTTP2",
|
||||||
|
"required": false,
|
||||||
|
"requires_restart": true,
|
||||||
|
"type": "bool",
|
||||||
|
"value": false,
|
||||||
|
"description": "Enable TLS, and by extension HTTP2. This enables server push, where required files are pushed to the web browser before they request them, allowing quicker page loads."
|
||||||
|
},
|
||||||
|
"tls_port": {
|
||||||
|
"name": "TLS Port",
|
||||||
|
"depends_true": "tls",
|
||||||
|
"required": false,
|
||||||
|
"requires_restart": true,
|
||||||
|
"type": "number",
|
||||||
|
"value": 8057,
|
||||||
|
"description": "Port to run TLS server on"
|
||||||
|
},
|
||||||
|
"tls_cert": {
|
||||||
|
"name": "Path to TLS Certificate",
|
||||||
|
"depends_true": "tls",
|
||||||
|
"required": false,
|
||||||
|
"requires_restart": true,
|
||||||
|
"type": "text",
|
||||||
|
"value": "",
|
||||||
|
"description": "Path to .crt file. See jfa-go wiki for more info."
|
||||||
|
},
|
||||||
|
"tls_key": {
|
||||||
|
"name": "Path to TLS Key file",
|
||||||
|
"depends_true": "tls",
|
||||||
|
"required": false,
|
||||||
|
"requires_restart": true,
|
||||||
|
"type": "text",
|
||||||
|
"value": "",
|
||||||
|
"description": "Path to .key file. See jfa-go wiki for more info."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"password_validation": {
|
"password_validation": {
|
||||||
"order": [],
|
"order": [],
|
||||||
"meta": {
|
"meta": {
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
window.notificationsEnabled = {{ .notifications }};
|
window.notificationsEnabled = {{ .notifications }};
|
||||||
window.emailEnabled = {{ .email_enabled }};
|
window.emailEnabled = {{ .email_enabled }};
|
||||||
window.ombiEnabled = {{ .ombiEnabled }};
|
window.ombiEnabled = {{ .ombiEnabled }};
|
||||||
window.usernamesEnabled = {{ .username }};
|
window.usernameEnabled = {{ .username }};
|
||||||
window.langFile = JSON.parse({{ .language }});
|
window.langFile = JSON.parse({{ .language }});
|
||||||
</script>
|
</script>
|
||||||
{{ template "header.html" . }}
|
{{ template "header.html" . }}
|
||||||
@ -99,7 +99,7 @@
|
|||||||
<span class="heading">{{ .strings.settingsRestartRequired }} <span class="modal-close">×</span></span>
|
<span class="heading">{{ .strings.settingsRestartRequired }} <span class="modal-close">×</span></span>
|
||||||
<p class="content pb-1">{{ .strings.settingsRestartRequiredDescription }}</p>
|
<p class="content pb-1">{{ .strings.settingsRestartRequiredDescription }}</p>
|
||||||
<div class="fr">
|
<div class="fr">
|
||||||
<span class="button ~info !normal" id="settings-apply-no-restart">{{ .strings.settingsApplyRestartLater }}</span>
|
<span class="button ~info !normal mb-half" id="settings-apply-no-restart">{{ .strings.settingsApplyRestartLater }}</span>
|
||||||
<span class="button ~critical !normal" id="settings-apply-restart">{{ .strings.settingsApplyRestartNow }}</span>
|
<span class="button ~critical !normal" id="settings-apply-restart">{{ .strings.settingsApplyRestartNow }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -22,17 +22,21 @@
|
|||||||
"delete": "Effacer",
|
"delete": "Effacer",
|
||||||
"submit": "Soumettre",
|
"submit": "Soumettre",
|
||||||
"name": "Nom",
|
"name": "Nom",
|
||||||
|
"date": "Date",
|
||||||
"username": "Nom d'utilisateur",
|
"username": "Nom d'utilisateur",
|
||||||
"password": "Mot de passe",
|
"password": "Mot de passe",
|
||||||
"emailAddress": "Addresse Email",
|
"emailAddress": "Addresse Email",
|
||||||
"lastActiveTime": "Dernière activité",
|
"lastActiveTime": "Dernière activité",
|
||||||
"from": "De",
|
"from": "De",
|
||||||
"user": "Utilisateur",
|
"user": "Utilisateur",
|
||||||
"aboutProgram": "A propros",
|
"aboutProgram": "A propos",
|
||||||
"version": "Version",
|
"version": "Version",
|
||||||
"commitNoun": "Commettre",
|
"commitNoun": "Commettre",
|
||||||
"newUser": "Nouvel utilisateur",
|
"newUser": "Nouvel utilisateur",
|
||||||
"profile": "Profil",
|
"profile": "Profil",
|
||||||
|
"success": "Succès",
|
||||||
|
"error": "Erreur",
|
||||||
|
"unknown": "Inconnu",
|
||||||
"modifySettings": "Modifier les paramètres",
|
"modifySettings": "Modifier les paramètres",
|
||||||
"modifySettingsDescription": "Appliquez les paramètres à partir d'un profil existant ou obtenez-les directement auprès d'un utilisateur.",
|
"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",
|
"applyHomescreenLayout": "Appliquer la disposition de l'écran d'accueil",
|
||||||
@ -55,7 +59,47 @@
|
|||||||
"addProfile": "Ajouter un profil",
|
"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, de nouveaux utilisateurs seront créés avec les paramètres. ",
|
||||||
"addProfileNameOf": "Nom de profil",
|
"addProfileNameOf": "Nom de profil",
|
||||||
"addProfileStoreHomescreenLayout": "Enregistrer la disposition de l'écran d'accueil"
|
"addProfileStoreHomescreenLayout": "Enregistrer la disposition de l'écran d'accueil",
|
||||||
|
|
||||||
|
"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:",
|
||||||
|
"notifyInviteExpiry": "À l'expiration",
|
||||||
|
"notifyUserCreation": "à la création de l'utilisateur"
|
||||||
|
},
|
||||||
|
"notifications": {
|
||||||
|
"changedEmailAddress": "Adresse e-mail modifiée de {n}.",
|
||||||
|
"userCreated": "L'utilisateur {n} a été créé.",
|
||||||
|
"createProfile": "Profil créé {n}.",
|
||||||
|
"saveSettings": "Les paramètres ont été enregistrés",
|
||||||
|
"setOmbiDefaults": "Valeurs par défaut de Ombi.",
|
||||||
|
"errorConnection": "Impossible de se connecter à jfa-go.",
|
||||||
|
"error401Unauthorized": "Non autorisé. Essayez d'actualiser la page.",
|
||||||
|
"errorSettingsAppliedNoHomescreenLayout": "Les paramètres ont été appliqués, mais l'application de la disposition de l'écran d'accueil a peut-être échoué.",
|
||||||
|
"errorHomescreenAppliedNoSettings": "La disposition de l'écran d'accueil a été appliquée, mais l'application des paramètres a peut-être échoué.",
|
||||||
|
"errorSettingsFailed": "L'application a échoué.",
|
||||||
|
"errorLoginBlank": "Le nom d'utilisateur et / ou le mot de passe sont vides",
|
||||||
|
"errorUnknown": "Erreur inconnue.",
|
||||||
|
"errorBlankFields": "Les champs sont vides",
|
||||||
|
"errorDeleteProfile": "Échec de la suppression du profil {n}",
|
||||||
|
"errorLoadProfiles": "Échec du chargement des profils.",
|
||||||
|
"errorCreateProfile": "Échec de la création du profil {n}",
|
||||||
|
"errorSetDefaultProfile": "Échec de la définition du profil par défaut",
|
||||||
|
"errorLoadUsers": "Échec du chargement des utilisateurs.",
|
||||||
|
"errorSaveSettings": "Impossible d'enregistrer les paramètres.",
|
||||||
|
"errorLoadSettings": "Échec du chargement des paramètres.",
|
||||||
|
"errorSetOmbiDefaults": "Impossible de stocker les valeurs par défaut d'Ombi.",
|
||||||
|
"errorLoadOmbiUsers": "Échec du chargement des utilisateurs Ombi.",
|
||||||
|
"errorChangedEmailAddress": "Impossible de modifier l'adresse e-mail de {n}.",
|
||||||
|
"errorFailureCheckLogs": "Échec (vérifier la console / les journaux)",
|
||||||
|
"errorPartialFailureCheckLogs": "Panne partielle (vérifier la console / les journaux)"
|
||||||
},
|
},
|
||||||
"quantityStrings": {
|
"quantityStrings": {
|
||||||
"modifySettingsFor": {
|
"modifySettingsFor": {
|
||||||
@ -73,6 +117,14 @@
|
|||||||
"deleteUser": {
|
"deleteUser": {
|
||||||
"singular": "Supprimer l'utilisateur",
|
"singular": "Supprimer l'utilisateur",
|
||||||
"plural": "Supprimer les utilisateurs"
|
"plural": "Supprimer les utilisateurs"
|
||||||
|
},
|
||||||
|
"deletedUser": {
|
||||||
|
"singular": "Supprimer {n} utilisateur.",
|
||||||
|
"plural": "Supprimer {n} utilisateurs."
|
||||||
|
},
|
||||||
|
"appliedSettings": {
|
||||||
|
"singular": "Appliquer le paramètre {n} utilisteur.",
|
||||||
|
"plural": "Appliquer les paramètres {n} utilisteurs."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,21 @@
|
|||||||
"author": "https://github.com/Cornichon420"
|
"author": "https://github.com/Cornichon420"
|
||||||
},
|
},
|
||||||
"userCreated": {
|
"userCreated": {
|
||||||
|
"title": "Notification : Utilisateur créé",
|
||||||
"aUserWasCreated": "Un utilisateur a été créé avec ce code {n}",
|
"aUserWasCreated": "Un utilisateur a été créé avec ce code {n}",
|
||||||
"name": "Nom",
|
"name": "Nom",
|
||||||
"emailAddress": "Adresse",
|
"emailAddress": "Adresse",
|
||||||
"time": "Date",
|
"time": "Date",
|
||||||
"notificationNotice": ""
|
"notificationNotice": ""
|
||||||
},
|
},
|
||||||
|
"inviteExpiry": {
|
||||||
|
"title": "Notification : Invitation expirée",
|
||||||
|
"inviteExpired": "Invitation expirée.",
|
||||||
|
"expiredAt": "Le code {n} a expiré à {n}.",
|
||||||
|
"notificationNotice": ""
|
||||||
|
},
|
||||||
"passwordReset": {
|
"passwordReset": {
|
||||||
|
"title": "Réinitialisation de mot du passe demandée - Jellyfin",
|
||||||
"helloUser": "Salut {n},",
|
"helloUser": "Salut {n},",
|
||||||
"someoneHasRequestedReset": "Quelqu'un vient de demander une réinitialisation du mot de passe via Jellyfin.",
|
"someoneHasRequestedReset": "Quelqu'un vient de demander une réinitialisation du mot de passe via Jellyfin.",
|
||||||
"ifItWasYou": "Si c'était bien toi, renseigne le code PIN en dessous.",
|
"ifItWasYou": "Si c'était bien toi, renseigne le code PIN en dessous.",
|
||||||
@ -19,14 +27,16 @@
|
|||||||
"pin": "PIN"
|
"pin": "PIN"
|
||||||
},
|
},
|
||||||
"userDeleted": {
|
"userDeleted": {
|
||||||
|
"title": "Ton compte a été désactivé - Jellyfin",
|
||||||
"yourAccountWasDeleted": "Ton compte Jellyfin a été supprimé.",
|
"yourAccountWasDeleted": "Ton compte Jellyfin a été supprimé.",
|
||||||
"reason": "Motif"
|
"reason": "Motif"
|
||||||
},
|
},
|
||||||
"inviteEmail": {
|
"inviteEmail": {
|
||||||
|
"title": "Invitation - Jellyfin",
|
||||||
"hello": "Salut",
|
"hello": "Salut",
|
||||||
"youHaveBeenInvited": "Tu a été invité à rejoindre Jellyfin.",
|
"youHaveBeenInvited": "Tu as été invité à rejoindre Jellyfin.",
|
||||||
"toJoin": "Pour continuer, suis le lien en dessous.",
|
"toJoin": "Pour continuer, suis le lien en dessous.",
|
||||||
"inviteExpiry": "L'invitation expirera le {n}, à {n}, sout dans {n}, alors fais vite !",
|
"inviteExpiry": "L'invitation expirera le {n}, à {n}, soit dans {n}, alors fais vite !",
|
||||||
"linkButton": "Lien"
|
"linkButton": "Lien"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
14
main.go
14
main.go
@ -331,7 +331,12 @@ func start(asDaemon, firstCall bool) {
|
|||||||
|
|
||||||
if !firstRun {
|
if !firstRun {
|
||||||
app.host = app.config.Section("ui").Key("host").String()
|
app.host = app.config.Section("ui").Key("host").String()
|
||||||
|
if app.config.Section("advanced").Key("tls").MustBool(false) {
|
||||||
|
app.info.Println("Using TLS/HTTP2")
|
||||||
|
app.port = app.config.Section("advanced").Key("tls_port").MustInt(8057)
|
||||||
|
} else {
|
||||||
app.port = app.config.Section("ui").Key("port").MustInt(8056)
|
app.port = app.config.Section("ui").Key("port").MustInt(8056)
|
||||||
|
}
|
||||||
|
|
||||||
if *HOST != app.host && *HOST != "" {
|
if *HOST != app.host && *HOST != "" {
|
||||||
app.host = *HOST
|
app.host = *HOST
|
||||||
@ -350,7 +355,6 @@ func start(asDaemon, firstCall bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
address = fmt.Sprintf("%s:%d", app.host, app.port)
|
address = fmt.Sprintf("%s:%d", app.host, app.port)
|
||||||
|
|
||||||
app.debug.Printf("Loaded config file \"%s\"", app.configPath)
|
app.debug.Printf("Loaded config file \"%s\"", app.configPath)
|
||||||
@ -625,9 +629,17 @@ func start(asDaemon, firstCall bool) {
|
|||||||
Handler: router,
|
Handler: router,
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
|
if app.config.Section("advanced").Key("tls").MustBool(false) {
|
||||||
|
cert := app.config.Section("advanced").Key("tls_cert").MustString("")
|
||||||
|
key := app.config.Section("advanced").Key("tls_key").MustString("")
|
||||||
|
if err := SRV.ListenAndServeTLS(cert, key); err != nil {
|
||||||
|
app.err.Printf("Failure serving: %s", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if err := SRV.ListenAndServe(); err != nil {
|
if err := SRV.ListenAndServe(); err != nil {
|
||||||
app.err.Printf("Failure serving: %s", err)
|
app.err.Printf("Failure serving: %s", err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
app.quit = make(chan os.Signal)
|
app.quit = make(chan os.Signal)
|
||||||
signal.Notify(app.quit, os.Interrupt)
|
signal.Notify(app.quit, os.Interrupt)
|
||||||
|
Loading…
Reference in New Issue
Block a user