mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-12-29 12:30:11 +00:00
Compare commits
3 Commits
84a556dc19
...
8fcb76cf97
Author | SHA1 | Date | |
---|---|---|---|
8fcb76cf97 | |||
c54e4811df | |||
4c6a9e9ad8 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,5 +6,6 @@ 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) 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) (and now [Emby](https://emby.media/)) that provides invite-based account creation as well as other features that make one's instance much easier to manage.
|
||||||
|
|
||||||
I chose to rewrite the python [jellyfin-accounts](https://github.com/hrfee/jellyfin-accounts) in Go mainly as a learning experience, but also to slightly improve speeds and efficiency.
|
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,6 +1050,7 @@ 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,5 +82,7 @@ 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,7 +65,15 @@
|
|||||||
"emby"
|
"emby"
|
||||||
],
|
],
|
||||||
"value": "jellyfin",
|
"value": "jellyfin",
|
||||||
"description": "Media server type."
|
"description": "Note: Emby integration works is missing some features, such as Password Resets."
|
||||||
|
},
|
||||||
|
"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."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1,57 +0,0 @@
|
|||||||
import json
|
|
||||||
|
|
||||||
with open("config-formatted.json", "r") as f:
|
|
||||||
config = json.load(f)
|
|
||||||
|
|
||||||
indent = 0
|
|
||||||
|
|
||||||
|
|
||||||
def writeln(ln):
|
|
||||||
global indent
|
|
||||||
if "}" in ln and "{" not in ln:
|
|
||||||
indent -= 1
|
|
||||||
s.write(("\t" * indent) + ln + "\n")
|
|
||||||
if "{" in ln and "}" not in ln:
|
|
||||||
indent += 1
|
|
||||||
|
|
||||||
|
|
||||||
with open("configStruct.go", "w") as s:
|
|
||||||
writeln("package main")
|
|
||||||
writeln("")
|
|
||||||
writeln("type Metadata struct{")
|
|
||||||
writeln('Name string `json:"name"`')
|
|
||||||
writeln('Description string `json:"description"`')
|
|
||||||
writeln("}")
|
|
||||||
writeln("")
|
|
||||||
writeln("type Config struct{")
|
|
||||||
if "order" in config:
|
|
||||||
writeln('Order []string `json:"order"`')
|
|
||||||
for section in [x for x in config.keys() if x != "order"]:
|
|
||||||
title = "".join([x.title() for x in section.split("_")])
|
|
||||||
writeln(title + " struct{")
|
|
||||||
if "order" in config[section]:
|
|
||||||
writeln('Order []string `json:"order"`')
|
|
||||||
if "meta" in config[section]:
|
|
||||||
writeln('Meta Metadata `json:"meta"`')
|
|
||||||
for setting in [
|
|
||||||
x for x in config[section].keys() if x != "order" and x != "meta"
|
|
||||||
]:
|
|
||||||
name = "".join([x.title() for x in setting.split("_")])
|
|
||||||
writeln(name + " struct{")
|
|
||||||
writeln('Name string `json:"name"`')
|
|
||||||
writeln('Required bool `json:"required"`')
|
|
||||||
writeln('Restart bool `json:"requires_restart"`')
|
|
||||||
writeln('Description string `json:"description"`')
|
|
||||||
writeln('Type string `json:"type"`')
|
|
||||||
dt = config[section][setting]["type"]
|
|
||||||
if dt == "select":
|
|
||||||
dt = "string"
|
|
||||||
writeln('Options []string `json:"options"`')
|
|
||||||
elif dt == "number":
|
|
||||||
dt = "int"
|
|
||||||
elif dt != "bool":
|
|
||||||
dt = "string"
|
|
||||||
writeln(f'Value {dt} `json:"value" cfg:"{setting}"`')
|
|
||||||
writeln("} " + f'`json:"{setting}" cfg:"{setting}"`')
|
|
||||||
writeln("} " + f'`json:"{section}"`')
|
|
||||||
writeln("}")
|
|
21
main.go
21
main.go
@ -39,6 +39,8 @@ 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 {
|
||||||
@ -282,12 +284,6 @@ 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)
|
||||||
@ -446,13 +442,12 @@ 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, things may not work."))
|
fmt.Println(aurora.Yellow("WARNING: Emby compatibility is experimental, and support is limited.\nPassword resets are not available."))
|
||||||
} else {
|
} else {
|
||||||
app.info.Println("Using Jellyfin server type")
|
app.info.Println("Using Jellyfin server type")
|
||||||
}
|
}
|
||||||
@ -526,6 +521,14 @@ 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()
|
||||||
@ -552,7 +555,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) {
|
if app.config.Section("password_resets").Key("enabled").MustBool(false) && serverType == mediabrowser.JellyfinServer {
|
||||||
go app.StartPWR()
|
go app.StartPWR()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
15
storage.go
15
storage.go
@ -58,6 +58,21 @@ 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