mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 04:14:39 +03:00
Build UI artifacts (#4824)
* Flag/env var for stash UI location * Include UI in build artifacts
This commit is contained in:
@@ -53,6 +53,28 @@ type Server struct {
|
||||
manager *manager.Manager
|
||||
}
|
||||
|
||||
// TODO - os.DirFS doesn't implement ReadDir, so re-implement it here
|
||||
// This can be removed when we upgrade go
|
||||
type osFS string
|
||||
|
||||
func (dir osFS) ReadDir(name string) ([]os.DirEntry, error) {
|
||||
fullname := string(dir) + "/" + name
|
||||
entries, err := os.ReadDir(fullname)
|
||||
if err != nil {
|
||||
var e *os.PathError
|
||||
if errors.As(err, &e) {
|
||||
// See comment in dirFS.Open.
|
||||
e.Path = name
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return entries, nil
|
||||
}
|
||||
|
||||
func (dir osFS) Open(name string) (fs.File, error) {
|
||||
return os.DirFS(string(dir)).Open(name)
|
||||
}
|
||||
|
||||
// Called at startup
|
||||
func Initialize() (*Server, error) {
|
||||
mgr := manager.GetInstance()
|
||||
@@ -213,25 +235,31 @@ func Initialize() (*Server, error) {
|
||||
r.Mount("/custom", getCustomRoutes(customServedFolders))
|
||||
}
|
||||
|
||||
customUILocation := cfg.GetCustomUILocation()
|
||||
staticUI := statigz.FileServer(ui.UIBox.(fs.ReadDirFS))
|
||||
var uiFS fs.FS
|
||||
var staticUI *statigz.Server
|
||||
customUILocation := cfg.GetUILocation()
|
||||
if customUILocation != "" {
|
||||
logger.Debugf("Serving UI from %s", customUILocation)
|
||||
uiFS = osFS(customUILocation)
|
||||
staticUI = statigz.FileServer(uiFS.(fs.ReadDirFS))
|
||||
} else {
|
||||
logger.Debug("Serving embedded UI")
|
||||
uiFS = ui.UIBox
|
||||
staticUI = statigz.FileServer(ui.UIBox.(fs.ReadDirFS))
|
||||
}
|
||||
|
||||
// Serve the web app
|
||||
r.HandleFunc("/*", func(w http.ResponseWriter, r *http.Request) {
|
||||
ext := path.Ext(r.URL.Path)
|
||||
|
||||
if customUILocation != "" {
|
||||
if r.URL.Path == "index.html" || ext == "" {
|
||||
r.URL.Path = "/"
|
||||
}
|
||||
|
||||
http.FileServer(http.Dir(customUILocation)).ServeHTTP(w, r)
|
||||
return
|
||||
if ext == ".html" || ext == "" {
|
||||
w.Header().Set("Content-Type", "text/html")
|
||||
setPageSecurityHeaders(w, r, pluginCache.ListPlugins())
|
||||
}
|
||||
|
||||
if ext == ".html" || ext == "" {
|
||||
if ext == "" || r.URL.Path == "/" || r.URL.Path == "/index.html" {
|
||||
themeColor := cfg.GetThemeColor()
|
||||
data, err := fs.ReadFile(ui.UIBox, "index.html")
|
||||
data, err := fs.ReadFile(uiFS, "index.html")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -241,9 +269,6 @@ func Initialize() (*Server, error) {
|
||||
indexHtml = strings.ReplaceAll(indexHtml, "%COLOR%", themeColor)
|
||||
indexHtml = strings.Replace(indexHtml, `<base href="/"`, fmt.Sprintf(`<base href="%s/"`, prefix), 1)
|
||||
|
||||
w.Header().Set("Content-Type", "text/html")
|
||||
setPageSecurityHeaders(w, r, pluginCache.ListPlugins())
|
||||
|
||||
utils.ServeStaticContent(w, r, []byte(indexHtml))
|
||||
} else {
|
||||
isStatic, _ := path.Match("/assets/*", r.URL.Path)
|
||||
|
||||
@@ -159,7 +159,10 @@ const (
|
||||
|
||||
// UI directory. Overrides to serve the UI from a specific location
|
||||
// rather than use the embedded UI.
|
||||
CustomUILocation = "custom_ui_location"
|
||||
UILocation = "ui_location"
|
||||
|
||||
// backwards compatible name
|
||||
LegacyCustomUILocation = "custom_ui_location"
|
||||
|
||||
// Gallery Cover Regex
|
||||
GalleryCoverRegex = "gallery_cover_regex"
|
||||
@@ -1057,8 +1060,12 @@ func (i *Config) GetCustomServedFolders() utils.URLMap {
|
||||
return i.getStringMapString(CustomServedFolders)
|
||||
}
|
||||
|
||||
func (i *Config) GetCustomUILocation() string {
|
||||
return i.getString(CustomUILocation)
|
||||
func (i *Config) GetUILocation() string {
|
||||
if ret := i.getString(UILocation); ret != "" {
|
||||
return ret
|
||||
}
|
||||
|
||||
return i.getString(LegacyCustomUILocation)
|
||||
}
|
||||
|
||||
// Interface options
|
||||
|
||||
@@ -72,7 +72,7 @@ func TestConcurrentConfigAccess(t *testing.T) {
|
||||
i.GetCredentials()
|
||||
i.Set(MaxSessionAge, i.GetMaxSessionAge())
|
||||
i.Set(CustomServedFolders, i.GetCustomServedFolders())
|
||||
i.Set(CustomUILocation, i.GetCustomUILocation())
|
||||
i.Set(LegacyCustomUILocation, i.GetUILocation())
|
||||
i.Set(MenuItems, i.GetMenuItems())
|
||||
i.Set(SoundOnPreview, i.GetSoundOnPreview())
|
||||
i.Set(WallShowTitle, i.GetWallShowTitle())
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/spf13/viper"
|
||||
@@ -26,6 +27,7 @@ func init() {
|
||||
pflag.Int("port", 9999, "port to serve from")
|
||||
pflag.StringVarP(&flags.configFilePath, "config", "c", "", "config file to use")
|
||||
pflag.BoolVar(&flags.nobrowser, "nobrowser", false, "Don't open a browser window after launch")
|
||||
pflag.StringP("ui-location", "u", "", "path to the webui")
|
||||
}
|
||||
|
||||
// Called at startup
|
||||
@@ -82,8 +84,8 @@ func InitializeEmpty() *Config {
|
||||
return instance
|
||||
}
|
||||
|
||||
func bindEnv(v *viper.Viper, key string) {
|
||||
if err := v.BindEnv(key); err != nil {
|
||||
func bindEnv(v *viper.Viper, key ...string) {
|
||||
if err := v.BindEnv(key...); err != nil {
|
||||
panic(fmt.Sprintf("unable to set environment key (%v): %v", key, err))
|
||||
}
|
||||
}
|
||||
@@ -91,18 +93,27 @@ func bindEnv(v *viper.Viper, key string) {
|
||||
func (i *Config) initOverrides() {
|
||||
v := i.overrides
|
||||
|
||||
// replace dashes with underscores in the flag names
|
||||
normalizeFn := pflag.CommandLine.GetNormalizeFunc()
|
||||
pflag.CommandLine.SetNormalizeFunc(func(f *pflag.FlagSet, name string) pflag.NormalizedName {
|
||||
result := normalizeFn(f, name)
|
||||
name = strings.ReplaceAll(string(result), "-", "_")
|
||||
return pflag.NormalizedName(name)
|
||||
})
|
||||
|
||||
if err := v.BindPFlags(pflag.CommandLine); err != nil {
|
||||
logger.Infof("failed to bind flags: %v", err)
|
||||
}
|
||||
|
||||
v.SetEnvPrefix("stash") // will be uppercased automatically
|
||||
bindEnv(v, "host") // STASH_HOST
|
||||
bindEnv(v, "port") // STASH_PORT
|
||||
bindEnv(v, "external_host") // STASH_EXTERNAL_HOST
|
||||
bindEnv(v, "generated") // STASH_GENERATED
|
||||
bindEnv(v, "metadata") // STASH_METADATA
|
||||
bindEnv(v, "cache") // STASH_CACHE
|
||||
bindEnv(v, "stash") // STASH_STASH
|
||||
v.SetEnvPrefix("stash") // will be uppercased automatically
|
||||
bindEnv(v, "host") // STASH_HOST
|
||||
bindEnv(v, "port") // STASH_PORT
|
||||
bindEnv(v, "external_host") // STASH_EXTERNAL_HOST
|
||||
bindEnv(v, "generated") // STASH_GENERATED
|
||||
bindEnv(v, "metadata") // STASH_METADATA
|
||||
bindEnv(v, "cache") // STASH_CACHE
|
||||
bindEnv(v, "stash") // STASH_STASH
|
||||
bindEnv(v, "ui_location", "STASH_UI") // STASH_UI
|
||||
}
|
||||
|
||||
func (i *Config) initConfig() error {
|
||||
|
||||
Reference in New Issue
Block a user