mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-12-29 12:30:11 +00:00
fully self-contained
paths are pretty janky, but it works. Also, [files]/lang_files now must be the path to a directory CONTAINING a "lang/" directory. I'll work around this at a later date.
This commit is contained in:
parent
1c06414320
commit
e1af1eeab5
6
Makefile
6
Makefile
@ -42,7 +42,7 @@ compile:
|
||||
go1.16rc1 mod download
|
||||
$(info Building)
|
||||
mkdir -p build
|
||||
CGO_ENABLED=0 go1.16rc1 build -o build/jfa-go *.go
|
||||
cd build && CGO_ENABLED=0 go1.16rc1 build -o ./jfa-go ../*.go
|
||||
|
||||
compress:
|
||||
upx --lzma build/jfa-go
|
||||
@ -67,5 +67,5 @@ copy:
|
||||
install:
|
||||
cp -r build $(DESTDIR)/jfa-go
|
||||
|
||||
all: configuration npm email version typescript bundle-css swagger compile copy
|
||||
debug: configuration npm email version ts-debug bundle-css swagger compile copy
|
||||
all: configuration npm email version typescript bundle-css swagger copy compile
|
||||
debug: configuration npm email version ts-debug bundle-css swagger copy compile
|
||||
|
@ -15,7 +15,7 @@ var emailEnabled = false
|
||||
func (app *appContext) GetPath(sect, key string) (fs.FS, string) {
|
||||
val := app.config.Section(sect).Key(key).MustString("")
|
||||
if strings.HasPrefix(val, "jfa-go:") {
|
||||
return app.localFS, strings.TrimPrefix(val, "jfa-go:")
|
||||
return localFS, "build/data/" + strings.TrimPrefix(val, "jfa-go:")
|
||||
}
|
||||
return app.systemFS, val
|
||||
}
|
||||
|
@ -867,7 +867,7 @@
|
||||
"requires_restart": true,
|
||||
"type": "text",
|
||||
"value": "",
|
||||
"description": "Useful if you want to customize the text in jfa-go. Should follow the same structure as the 'lang' directory, which you can see on GitHub."
|
||||
"description": "The path to a directory CONTAINING a 'lang/' directory, which follow the same form as the internal one. See GitHub for more info."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
4
go.mod
4
go.mod
@ -1,6 +1,6 @@
|
||||
module github.com/hrfee/jfa-go
|
||||
|
||||
go 1.14
|
||||
go 1.16
|
||||
|
||||
replace github.com/hrfee/jfa-go/docs => ./docs
|
||||
|
||||
@ -50,8 +50,6 @@ require (
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777 // indirect
|
||||
golang.org/x/sys v0.0.0-20210123111255-9b0068b26619 // indirect
|
||||
golang.org/x/text v0.3.5 // indirect
|
||||
golang.org/x/tools v0.1.1-0.20210129181147-0cef57b5b584 // indirect
|
||||
golang.org/x/tools/gopls v0.0.0-20210201165201-19db92ec3be1 // indirect
|
||||
google.golang.org/protobuf v1.25.0 // indirect
|
||||
gopkg.in/ini.v1 v1.62.0
|
||||
)
|
||||
|
30
go.sum
30
go.sum
@ -448,40 +448,10 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59 h1:QjA/9ArTfVTLfEhClDCG7SGrZkZixxWpwNCDiwJfh88=
|
||||
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200410194907-79a7a3126eef/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200923182640-463111b69878 h1:VUw1+Jf6KJPf82mbTQMia6HCnNMv2BbAipkEZ4KTcqQ=
|
||||
golang.org/x/tools v0.0.0-20200923182640-463111b69878/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||
golang.org/x/tools v0.0.0-20200924182824-0f1c53950d78 h1:3JUoxVhcskhsIDEc7vg0MUUEpmPPN5TfG+E97z/Fn90=
|
||||
golang.org/x/tools v0.0.0-20200924182824-0f1c53950d78/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||
golang.org/x/tools v0.0.0-20200929191002-f1e51e6b9437 h1:XSFqH8m531iIGazX5lrUC9j3slbwsZ1GFByqdUrLqmI=
|
||||
golang.org/x/tools v0.0.0-20200929191002-f1e51e6b9437/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||
golang.org/x/tools v0.0.0-20201008184944-d01b322e6f06 h1:w9ail9jFLaySAm61Zjhciu0LQ5i8YTy2pimlNLx4uuk=
|
||||
golang.org/x/tools v0.0.0-20201008184944-d01b322e6f06/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||
golang.org/x/tools v0.0.0-20201017001424-6003fad69a88 h1:ZB1XYzdDo7c/O48jzjMkvIjnC120Z9/CwgDWhePjQdQ=
|
||||
golang.org/x/tools v0.0.0-20201017001424-6003fad69a88/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||
golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9 h1:sEvmEcJVKBNUvgCUClbUQeHOAa9U0I2Ce1BooMvVCY4=
|
||||
golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201103235415-b653051172e4 h1:Qe0EMgvVYb6tmJhJHljCj3gS96hvSTkGNaIzp/ivq10=
|
||||
golang.org/x/tools v0.0.0-20201103235415-b653051172e4/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201113202037-1643af1435f3 h1:7R7+wzd5VuLvCNyHZ/MG511kkoP/DBEzkbh8qUsFbY8=
|
||||
golang.org/x/tools v0.0.0-20201113202037-1643af1435f3/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201114224030-61ea331ec02b h1:Ych5r0Z6MLML1fgf5hTg9p5bV56Xqx9xv9hLgMBATWs=
|
||||
golang.org/x/tools v0.0.0-20201114224030-61ea331ec02b/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201120155355-20be4ac4bd6e h1:t96dS3DO8DGjawSLJL/HIdz8CycAd2v07XxqB3UPTi0=
|
||||
golang.org/x/tools v0.0.0-20201120155355-20be4ac4bd6e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210104081019-d8d6ddbec6ee h1:5xKxdl/RhlelmSPaxyVeq5PYSmJ4H14yeQT58qP1F6o=
|
||||
golang.org/x/tools v0.0.0-20210104081019-d8d6ddbec6ee/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.1-0.20210129181147-0cef57b5b584 h1:JAI5SUo/oOtQXK4jvtjJMlwF5opt8qBUpxGa86SJ6zU=
|
||||
golang.org/x/tools v0.1.1-0.20210129181147-0cef57b5b584/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools/gopls v0.0.0-20210201165201-19db92ec3be1 h1:YRvjnCA/wBOOkQAEKC5ts16/1IJ+NEO9eevhfDF5ues=
|
||||
golang.org/x/tools/gopls v0.0.0-20210201165201-19db92ec3be1/go.mod h1:DWl5nefYvX46i2mLQVu6Ud0ycJQ3HNPbQKzUHT3VUek=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
50
main.go
50
main.go
@ -3,6 +3,7 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"embed"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
@ -50,6 +51,12 @@ type User struct {
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
//go:embed build/data build/data/html build/data/web build/data/web/css build/data/web/js build/data/web/js/ts
|
||||
var localFS embed.FS
|
||||
|
||||
//go:embed lang/common lang/admin lang/email lang/form lang/setup
|
||||
var langFS embed.FS
|
||||
|
||||
// contains everything the application needs, essentially. Wouldn't do this in the future.
|
||||
type appContext struct {
|
||||
// defaults *Config
|
||||
@ -59,8 +66,6 @@ type appContext struct {
|
||||
configBase settings
|
||||
dataPath string
|
||||
systemFS fs.FS
|
||||
localFS fs.FS
|
||||
langFS fs.FS
|
||||
webFS httpFS
|
||||
cssClass string
|
||||
jellyfinLogin bool
|
||||
@ -85,8 +90,8 @@ type appContext struct {
|
||||
|
||||
func (app *appContext) loadHTML(router *gin.Engine) {
|
||||
customPath := app.config.Section("files").Key("html_templates").MustString("")
|
||||
templatePath := "html"
|
||||
htmlFiles, err := fs.ReadDir(app.localFS, templatePath)
|
||||
templatePath := "build/data/html"
|
||||
htmlFiles, err := fs.ReadDir(localFS, templatePath)
|
||||
if err != nil {
|
||||
app.err.Fatalf("Couldn't access template directory: \"%s\"", templatePath)
|
||||
return
|
||||
@ -101,7 +106,7 @@ func (app *appContext) loadHTML(router *gin.Engine) {
|
||||
loadFiles[i] = filepath.Join(filepath.Join(customPath, f.Name()))
|
||||
}
|
||||
}
|
||||
tmpl, err := template.ParseFS(app.localFS, loadFiles...)
|
||||
tmpl, err := template.ParseFS(localFS, loadFiles...)
|
||||
if err != nil {
|
||||
app.err.Fatalf("Failed to load templates: %v", err)
|
||||
}
|
||||
@ -200,16 +205,15 @@ func start(asDaemon, firstCall bool) {
|
||||
userConfigDir, _ := os.UserConfigDir()
|
||||
app.dataPath = filepath.Join(userConfigDir, "jfa-go")
|
||||
app.configPath = filepath.Join(app.dataPath, "config.ini")
|
||||
executable, _ := os.Executable()
|
||||
app.localFS = os.DirFS(filepath.Join(filepath.Dir(executable), "data"))
|
||||
app.langFS = os.DirFS(filepath.Join(filepath.Dir(executable), "data", "lang"))
|
||||
// executable, _ := os.Executable()
|
||||
// localFS = os.DirFS(filepath.Join(filepath.Dir(executable), "data"))
|
||||
// langFS = os.DirFS(filepath.Join(filepath.Dir(executable), "data", "lang"))
|
||||
app.systemFS = os.DirFS("/")
|
||||
wfs := os.DirFS(filepath.Join(filepath.Dir(executable), "data", "web"))
|
||||
// wfs := os.DirFS(filepath.Join(filepath.Dir(executable), "data", "web"))
|
||||
app.webFS = httpFS{
|
||||
hfs: http.FS(wfs),
|
||||
fs: wfs,
|
||||
hfs: http.FS(localFS),
|
||||
fs: localFS,
|
||||
}
|
||||
app.webFS.fs = wfs
|
||||
|
||||
app.info = log.New(os.Stdout, "[INFO] ", log.Ltime)
|
||||
app.err = log.New(os.Stdout, "[ERROR] ", log.Ltime|log.Lshortfile)
|
||||
@ -266,7 +270,7 @@ func start(asDaemon, firstCall bool) {
|
||||
}
|
||||
if _, err := os.Stat(app.configPath); os.IsNotExist(err) {
|
||||
firstRun = true
|
||||
dConfig, err := fs.ReadFile(app.localFS, "config-default.ini")
|
||||
dConfig, err := fs.ReadFile(localFS, "build/data/config-default.ini")
|
||||
if err != nil {
|
||||
app.err.Fatalf("Couldn't find default config file")
|
||||
}
|
||||
@ -341,16 +345,16 @@ func start(asDaemon, firstCall bool) {
|
||||
}()
|
||||
}
|
||||
|
||||
app.storage.lang.CommonPath = "common"
|
||||
app.storage.lang.FormPath = "form"
|
||||
app.storage.lang.AdminPath = "admin"
|
||||
app.storage.lang.EmailPath = "email"
|
||||
app.storage.lang.CommonPath = "lang/common"
|
||||
app.storage.lang.FormPath = "lang/form"
|
||||
app.storage.lang.AdminPath = "lang/admin"
|
||||
app.storage.lang.EmailPath = "lang/email"
|
||||
externalLang := app.config.Section("files").Key("lang_files").MustString("")
|
||||
var err error
|
||||
if externalLang == "" {
|
||||
err = app.storage.loadLang(app.langFS)
|
||||
err = app.storage.loadLang(langFS)
|
||||
} else {
|
||||
err = app.storage.loadLang(app.langFS, os.DirFS(externalLang))
|
||||
err = app.storage.loadLang(langFS, os.DirFS(externalLang))
|
||||
}
|
||||
if err != nil {
|
||||
app.info.Fatalf("Failed to load language files: %+v\n", err)
|
||||
@ -430,8 +434,8 @@ func start(asDaemon, firstCall bool) {
|
||||
|
||||
}
|
||||
|
||||
app.configBasePath = "config-base.json"
|
||||
configBase, _ := fs.ReadFile(app.localFS, app.configBasePath)
|
||||
app.configBasePath = "build/data/config-base.json"
|
||||
configBase, _ := fs.ReadFile(localFS, app.configBasePath)
|
||||
json.Unmarshal(configBase, &app.configBase)
|
||||
|
||||
themes := map[string]string{
|
||||
@ -579,8 +583,8 @@ func start(asDaemon, firstCall bool) {
|
||||
} else {
|
||||
debugMode = false
|
||||
address = "0.0.0.0:8056"
|
||||
app.storage.lang.SetupPath = filepath.Join("lang", "setup")
|
||||
err := app.storage.loadLangSetup()
|
||||
app.storage.lang.SetupPath = "lang/setup"
|
||||
err := app.storage.loadLangSetup(langFS)
|
||||
if err != nil {
|
||||
app.info.Fatalf("Failed to load language files: %+v\n", err)
|
||||
}
|
||||
|
8
setup.go
8
setup.go
@ -120,6 +120,7 @@ func (st *Storage) loadLangSetup(filesystems ...fs.FS) error {
|
||||
return err
|
||||
}
|
||||
english = st.lang.Setup["en-us"]
|
||||
setupLoaded := false
|
||||
for _, filesystem := range filesystems {
|
||||
files, err := fs.ReadDir(filesystem, st.lang.SetupPath)
|
||||
if err != nil {
|
||||
@ -128,11 +129,14 @@ func (st *Storage) loadLangSetup(filesystems ...fs.FS) error {
|
||||
for _, f := range files {
|
||||
if f.Name() != "en-us.json" {
|
||||
err = load(filesystem, f.Name())
|
||||
if err != nil {
|
||||
return err
|
||||
if err == nil {
|
||||
setupLoaded = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !setupLoaded {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"strings"
|
||||
@ -14,12 +15,13 @@ type httpFS struct {
|
||||
}
|
||||
|
||||
func (f httpFS) Open(name string) (http.File, error) {
|
||||
return f.hfs.Open(name)
|
||||
fmt.Println("build/data/web" + name)
|
||||
return f.hfs.Open("build/data/web" + name)
|
||||
}
|
||||
|
||||
func (f httpFS) Exists(prefix string, filepath string) bool {
|
||||
if p := strings.TrimPrefix(filepath, prefix); len(p) < len(filepath) {
|
||||
stats, err := fs.Stat(f.fs, p)
|
||||
stats, err := fs.Stat(f.fs, "build/data/web/"+p)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user