This commit is contained in:
WithoutPants 2025-12-04 18:27:04 -05:00 committed by GitHub
commit 1a26c61b42
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 59 additions and 6 deletions

View file

@ -11,6 +11,7 @@ import (
"net/http" "net/http"
"os" "os"
"path" "path"
"path/filepath"
"runtime/debug" "runtime/debug"
"strconv" "strconv"
"strings" "strings"
@ -255,6 +256,9 @@ func Initialize() (*Server, error) {
staticUI = statigz.FileServer(ui.UIBox.(fs.ReadDirFS)) staticUI = statigz.FileServer(ui.UIBox.(fs.ReadDirFS))
} }
// handle favicon override
r.HandleFunc("/favicon.ico", handleFavicon(staticUI))
// Serve the web app // Serve the web app
r.HandleFunc("/*", func(w http.ResponseWriter, r *http.Request) { r.HandleFunc("/*", func(w http.ResponseWriter, r *http.Request) {
ext := path.Ext(r.URL.Path) ext := path.Ext(r.URL.Path)
@ -295,6 +299,31 @@ func Initialize() (*Server, error) {
return server, nil return server, nil
} }
func handleFavicon(staticUI *statigz.Server) func(w http.ResponseWriter, r *http.Request) {
mgr := manager.GetInstance()
cfg := mgr.Config
// check if favicon.ico exists in the config directory
// if so, use that
// otherwise, use the embedded one
iconPath := filepath.Join(cfg.GetConfigPath(), "favicon.ico")
exists, _ := fsutil.FileExists(iconPath)
if exists {
logger.Debugf("Using custom favicon at %s", iconPath)
}
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", "no-cache")
if exists {
http.ServeFile(w, r, iconPath)
} else {
staticUI.ServeHTTP(w, r)
}
}
}
// Start starts the server. It listens on the configured address and port. // Start starts the server. It listens on the configured address and port.
// It calls ListenAndServeTLS if TLS is configured, otherwise it calls ListenAndServe. // It calls ListenAndServeTLS if TLS is configured, otherwise it calls ListenAndServe.
// Calls to Start are blocked until the server is shutdown. // Calls to Start are blocked until the server is shutdown.

View file

@ -307,7 +307,8 @@ export const App: React.FC = () => {
); );
} }
const titleProps = makeTitleProps(); const title = config.data?.configuration.ui.title || "Stash";
const titleProps = makeTitleProps(title);
if (!messages) { if (!messages) {
return null; return null;

View file

@ -248,6 +248,14 @@ export const SettingsInterfacePanel: React.FC = PatchComponent(
onChange={(v) => saveInterface({ sfwContentMode: v })} onChange={(v) => saveInterface({ sfwContentMode: v })}
/> />
<StringSetting
id="custom-title"
headingID="config.ui.custom_title.heading"
subHeadingID="config.ui.custom_title.description"
value={ui.title ?? ""}
onChange={(v) => saveUI({ title: v })}
/>
<div className="setting-group"> <div className="setting-group">
<div className="setting"> <div className="setting">
<div> <div>

View file

@ -103,6 +103,8 @@ export interface IUIConfig {
defaultFilters?: DefaultFilters; defaultFilters?: DefaultFilters;
taggerConfig?: ITaggerConfig; taggerConfig?: ITaggerConfig;
title?: string;
} }
export function getFrontPageContent( export function getFrontPageContent(

View file

@ -165,6 +165,12 @@ The following environment variables are also supported:
|----------------------|---------| |----------------------|---------|
| `STASH_SQLITE_CACHE_SIZE` | Sets the SQLite cache size. See https://www.sqlite.org/pragma.html#pragma_cache_size. Default is `-2000` which is 2MB. | | `STASH_SQLITE_CACHE_SIZE` | Sets the SQLite cache size. See https://www.sqlite.org/pragma.html#pragma_cache_size. Default is `-2000` which is 2MB. |
### Custom favicon
You can provide a custom favicon by placing a `favicon.ico` file in the configuration directory. The configuration directory is located alongside the `config.yml` file.
When a custom favicon is provided, it will be served instead of the default embedded favicon.
### Custom served folders ### Custom served folders
Custom served folders are served when the server handles a request with the `/custom` URL prefix. The following is an example configuration: Custom served folders are served when the server handles a request with the `/custom` URL prefix. The following is an example configuration:

View file

@ -1,10 +1,13 @@
import { MessageDescriptor, useIntl } from "react-intl"; import { MessageDescriptor, useIntl } from "react-intl";
import { useConfigurationContext } from "./Config";
export const TITLE = "Stash"; export const TITLE = "Stash";
export const TITLE_SEPARATOR = " | "; export const TITLE_SEPARATOR = " | ";
export function useTitleProps(...messages: (string | MessageDescriptor)[]) { export function useTitleProps(...messages: (string | MessageDescriptor)[]) {
const intl = useIntl(); const intl = useIntl();
const config = useConfigurationContext();
const title = config.configuration.ui.title || TITLE;
const parts = messages.map((msg) => { const parts = messages.map((msg) => {
if (typeof msg === "object") { if (typeof msg === "object") {
@ -14,13 +17,13 @@ export function useTitleProps(...messages: (string | MessageDescriptor)[]) {
} }
}); });
return makeTitleProps(...parts); return makeTitleProps(title, ...parts);
} }
export function makeTitleProps(...parts: string[]) { export function makeTitleProps(title: string, ...parts: string[]) {
const title = [...parts, TITLE].join(TITLE_SEPARATOR); const fullTitle = [...parts, title].join(TITLE_SEPARATOR);
return { return {
titleTemplate: `%s | ${title}`, titleTemplate: `%s | ${fullTitle}`,
defaultTitle: title, defaultTitle: fullTitle,
}; };
} }

View file

@ -621,6 +621,10 @@
"heading": "Custom localisation", "heading": "Custom localisation",
"option_label": "Custom localisation enabled" "option_label": "Custom localisation enabled"
}, },
"custom_title": {
"description": "Custom text to append to the page title. If empty, defaults to 'Stash'.",
"heading": "Custom Title"
},
"delete_options": { "delete_options": {
"description": "Default settings when deleting images, galleries, and scenes.", "description": "Default settings when deleting images, galleries, and scenes.",
"heading": "Delete Options", "heading": "Delete Options",