mirror of
https://github.com/hrfee/jfa-go.git
synced 2025-01-01 14:00:12 +00:00
Compare commits
No commits in common. "8fcb76cf97c16e0635fc7e3fef2489813a110779" and "84a556dc19be70d43eb0ba4419929a2c082b3216" have entirely different histories.
8fcb76cf97
...
84a556dc19
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,6 +6,5 @@ data/
|
|||||||
version.go
|
version.go
|
||||||
notes
|
notes
|
||||||
docs/*
|
docs/*
|
||||||
lang/langtostruct.py
|
|
||||||
config-payload.json
|
config-payload.json
|
||||||
!docs/go.mod
|
!docs/go.mod
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# ![jfa-go](images/banner.svg)
|
# ![jfa-go](images/banner.svg)
|
||||||
|
|
||||||
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.
|
jfa-go is a user management app for [Jellyfin](https://github.com/jellyfin/jellyfin) that provides invite-based account creation as well as other features that make one's instance much easier to manage.
|
||||||
|
|
||||||
I chose to rewrite the python [jellyfin-accounts](https://github.com/hrfee/jellyfin-accounts) in Go mainly as a learning experience, but also to slightly improve speeds and efficiency.
|
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.
|
||||||
|
|
||||||
|
1
api.go
1
api.go
@ -1050,7 +1050,6 @@ func (app *appContext) ApplySettings(gc *gin.Context) {
|
|||||||
"homescreen": map[string]string{},
|
"homescreen": map[string]string{},
|
||||||
}
|
}
|
||||||
for _, id := range req.ApplyTo {
|
for _, id := range req.ApplyTo {
|
||||||
fmt.Printf("%+v\n", policy)
|
|
||||||
status, err := app.jf.SetPolicy(id, policy)
|
status, err := app.jf.SetPolicy(id, policy)
|
||||||
if !(status == 200 || status == 204) || err != nil {
|
if !(status == 200 || status == 204) || err != nil {
|
||||||
errors["policy"][id] = fmt.Sprintf("%d: %s", status, err)
|
errors["policy"][id] = fmt.Sprintf("%d: %s", status, err)
|
||||||
|
@ -82,7 +82,5 @@ func (app *appContext) loadConfig() error {
|
|||||||
|
|
||||||
app.email = NewEmailer(app)
|
app.email = NewEmailer(app)
|
||||||
|
|
||||||
substituteStrings = app.config.Section("jellyfin").Key("substitute_jellyfin_strings").MustString("")
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -65,15 +65,7 @@
|
|||||||
"emby"
|
"emby"
|
||||||
],
|
],
|
||||||
"value": "jellyfin",
|
"value": "jellyfin",
|
||||||
"description": "Note: Emby integration works is missing some features, such as Password Resets."
|
"description": "Media server type."
|
||||||
},
|
|
||||||
"substitute_jellyfin_strings": {
|
|
||||||
"name": "Substitute occurrences of \"Jellyfin\"",
|
|
||||||
"required": false,
|
|
||||||
"requires_restart": true,
|
|
||||||
"type": "text",
|
|
||||||
"value": "",
|
|
||||||
"description": "Optionally substitute occurrences of \"Jellyfin\" in the account creation form with this. May result in bad grammar."
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
57
config/jsontostruct.py
Normal file
57
config/jsontostruct.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
|
with open("config-formatted.json", "r") as f:
|
||||||
|
config = json.load(f)
|
||||||
|
|
||||||
|
indent = 0
|
||||||
|
|
||||||
|
|
||||||
|
def writeln(ln):
|
||||||
|
global indent
|
||||||
|
if "}" in ln and "{" not in ln:
|
||||||
|
indent -= 1
|
||||||
|
s.write(("\t" * indent) + ln + "\n")
|
||||||
|
if "{" in ln and "}" not in ln:
|
||||||
|
indent += 1
|
||||||
|
|
||||||
|
|
||||||
|
with open("configStruct.go", "w") as s:
|
||||||
|
writeln("package main")
|
||||||
|
writeln("")
|
||||||
|
writeln("type Metadata struct{")
|
||||||
|
writeln('Name string `json:"name"`')
|
||||||
|
writeln('Description string `json:"description"`')
|
||||||
|
writeln("}")
|
||||||
|
writeln("")
|
||||||
|
writeln("type Config struct{")
|
||||||
|
if "order" in config:
|
||||||
|
writeln('Order []string `json:"order"`')
|
||||||
|
for section in [x for x in config.keys() if x != "order"]:
|
||||||
|
title = "".join([x.title() for x in section.split("_")])
|
||||||
|
writeln(title + " struct{")
|
||||||
|
if "order" in config[section]:
|
||||||
|
writeln('Order []string `json:"order"`')
|
||||||
|
if "meta" in config[section]:
|
||||||
|
writeln('Meta Metadata `json:"meta"`')
|
||||||
|
for setting in [
|
||||||
|
x for x in config[section].keys() if x != "order" and x != "meta"
|
||||||
|
]:
|
||||||
|
name = "".join([x.title() for x in setting.split("_")])
|
||||||
|
writeln(name + " struct{")
|
||||||
|
writeln('Name string `json:"name"`')
|
||||||
|
writeln('Required bool `json:"required"`')
|
||||||
|
writeln('Restart bool `json:"requires_restart"`')
|
||||||
|
writeln('Description string `json:"description"`')
|
||||||
|
writeln('Type string `json:"type"`')
|
||||||
|
dt = config[section][setting]["type"]
|
||||||
|
if dt == "select":
|
||||||
|
dt = "string"
|
||||||
|
writeln('Options []string `json:"options"`')
|
||||||
|
elif dt == "number":
|
||||||
|
dt = "int"
|
||||||
|
elif dt != "bool":
|
||||||
|
dt = "string"
|
||||||
|
writeln(f'Value {dt} `json:"value" cfg:"{setting}"`')
|
||||||
|
writeln("} " + f'`json:"{setting}" cfg:"{setting}"`')
|
||||||
|
writeln("} " + f'`json:"{section}"`')
|
||||||
|
writeln("}")
|
21
main.go
21
main.go
@ -39,8 +39,6 @@ var serverTypes = map[string]string{
|
|||||||
"jellyfin": "Jellyfin",
|
"jellyfin": "Jellyfin",
|
||||||
"emby": "Emby (experimental)",
|
"emby": "Emby (experimental)",
|
||||||
}
|
}
|
||||||
var serverType = mediabrowser.JellyfinServer
|
|
||||||
var substituteStrings = ""
|
|
||||||
|
|
||||||
// User is used for auth purposes.
|
// User is used for auth purposes.
|
||||||
type User struct {
|
type User struct {
|
||||||
@ -284,6 +282,12 @@ func start(asDaemon, firstCall bool) {
|
|||||||
if app.loadConfig() != nil {
|
if app.loadConfig() != nil {
|
||||||
app.err.Fatalf("Failed to load config file \"%s\"", app.configPath)
|
app.err.Fatalf("Failed to load config file \"%s\"", app.configPath)
|
||||||
}
|
}
|
||||||
|
lang := app.config.Section("ui").Key("language").MustString("en-us")
|
||||||
|
app.storage.lang.FormPath = filepath.Join(app.localPath, "lang", "form", lang+".json")
|
||||||
|
if _, err := os.Stat(app.storage.lang.FormPath); os.IsNotExist(err) {
|
||||||
|
app.storage.lang.FormPath = filepath.Join(app.localPath, "lang", "form", "en-us.json")
|
||||||
|
}
|
||||||
|
app.storage.loadLang()
|
||||||
app.version = app.config.Section("jellyfin").Key("version").String()
|
app.version = app.config.Section("jellyfin").Key("version").String()
|
||||||
// read from config...
|
// read from config...
|
||||||
debugMode = app.config.Section("ui").Key("debug").MustBool(false)
|
debugMode = app.config.Section("ui").Key("debug").MustBool(false)
|
||||||
@ -442,12 +446,13 @@ func start(asDaemon, firstCall bool) {
|
|||||||
server := app.config.Section("jellyfin").Key("server").String()
|
server := app.config.Section("jellyfin").Key("server").String()
|
||||||
cacheTimeout := int(app.config.Section("jellyfin").Key("cache_timeout").MustUint(30))
|
cacheTimeout := int(app.config.Section("jellyfin").Key("cache_timeout").MustUint(30))
|
||||||
stringServerType := app.config.Section("jellyfin").Key("type").String()
|
stringServerType := app.config.Section("jellyfin").Key("type").String()
|
||||||
|
serverType := mediabrowser.JellyfinServer
|
||||||
timeoutHandler := common.NewTimeoutHandler("Jellyfin", server, true)
|
timeoutHandler := common.NewTimeoutHandler("Jellyfin", server, true)
|
||||||
if stringServerType == "emby" {
|
if stringServerType == "emby" {
|
||||||
serverType = mediabrowser.EmbyServer
|
serverType = mediabrowser.EmbyServer
|
||||||
timeoutHandler = common.NewTimeoutHandler("Emby", server, true)
|
timeoutHandler = common.NewTimeoutHandler("Emby", server, true)
|
||||||
app.info.Println("Using Emby server type")
|
app.info.Println("Using Emby server type")
|
||||||
fmt.Println(aurora.Yellow("WARNING: Emby compatibility is experimental, and support is limited.\nPassword resets are not available."))
|
fmt.Println(aurora.Yellow("WARNING: Emby compatibility is experimental, things may not work."))
|
||||||
} else {
|
} else {
|
||||||
app.info.Println("Using Jellyfin server type")
|
app.info.Println("Using Jellyfin server type")
|
||||||
}
|
}
|
||||||
@ -521,14 +526,6 @@ func start(asDaemon, firstCall bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lang := app.config.Section("ui").Key("language").MustString("en-us")
|
|
||||||
app.storage.lang.FormPath = filepath.Join(app.localPath, "lang", "form", lang+".json")
|
|
||||||
if _, err := os.Stat(app.storage.lang.FormPath); os.IsNotExist(err) {
|
|
||||||
app.storage.lang.FormPath = filepath.Join(app.localPath, "lang", "form", "en-us.json")
|
|
||||||
}
|
|
||||||
app.storage.loadLang()
|
|
||||||
|
|
||||||
app.authJf, _ = mediabrowser.NewServer(serverType, server, "jfa-go", app.version, "auth", "auth", timeoutHandler, cacheTimeout)
|
app.authJf, _ = mediabrowser.NewServer(serverType, server, "jfa-go", app.version, "auth", "auth", timeoutHandler, cacheTimeout)
|
||||||
|
|
||||||
app.loadStrftime()
|
app.loadStrftime()
|
||||||
@ -555,7 +552,7 @@ func start(asDaemon, firstCall bool) {
|
|||||||
inviteDaemon := newRepeater(time.Duration(60*time.Second), app)
|
inviteDaemon := newRepeater(time.Duration(60*time.Second), app)
|
||||||
go inviteDaemon.run()
|
go inviteDaemon.run()
|
||||||
|
|
||||||
if app.config.Section("password_resets").Key("enabled").MustBool(false) && serverType == mediabrowser.JellyfinServer {
|
if app.config.Section("password_resets").Key("enabled").MustBool(false) {
|
||||||
go app.StartPWR()
|
go app.StartPWR()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
15
storage.go
15
storage.go
@ -58,21 +58,6 @@ func (st *Storage) storeInvites() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (st *Storage) loadLang() error {
|
func (st *Storage) loadLang() error {
|
||||||
if substituteStrings != "" {
|
|
||||||
var file []byte
|
|
||||||
var err error
|
|
||||||
file, err = ioutil.ReadFile(st.lang.FormPath)
|
|
||||||
if err != nil {
|
|
||||||
file = []byte("{}")
|
|
||||||
}
|
|
||||||
// Replace Jellyfin with emby on form
|
|
||||||
file = []byte(strings.ReplaceAll(string(file), "Jellyfin", substituteStrings))
|
|
||||||
err = json.Unmarshal(file, &st.lang.Form)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("ERROR: Failed to read \"%s\": %s", st.lang.FormPath, err)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err := loadJSON(st.lang.FormPath, &st.lang.Form)
|
err := loadJSON(st.lang.FormPath, &st.lang.Form)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
Loading…
Reference in New Issue
Block a user