Support Javascript injection (#3132)

This commit is contained in:
CJ 2022-11-16 16:37:06 -06:00 committed by GitHub
parent 3a63f1f9b7
commit ca9c8e0a34
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 125 additions and 0 deletions

View File

@ -63,6 +63,8 @@ fragment ConfigInterfaceData on ConfigInterfaceResult {
showStudioAsText showStudioAsText
css css
cssEnabled cssEnabled
javascript
javascriptEnabled
customLocales customLocales
customLocalesEnabled customLocalesEnabled
language language

View File

@ -264,6 +264,10 @@ input ConfigInterfaceInput {
css: String css: String
cssEnabled: Boolean cssEnabled: Boolean
"""Custom Javascript"""
javascript: String
javascriptEnabled: Boolean
"""Custom Locales""" """Custom Locales"""
customLocales: String customLocales: String
customLocalesEnabled: Boolean customLocalesEnabled: Boolean
@ -330,6 +334,10 @@ type ConfigInterfaceResult {
css: String css: String
cssEnabled: Boolean cssEnabled: Boolean
"""Custom Javascript"""
javascript: String
javascriptEnabled: Boolean
"""Custom Locales""" """Custom Locales"""
customLocales: String customLocales: String
customLocalesEnabled: Boolean customLocalesEnabled: Boolean

View File

@ -365,6 +365,12 @@ func (r *mutationResolver) ConfigureInterface(ctx context.Context, input ConfigI
setBool(config.CSSEnabled, input.CSSEnabled) setBool(config.CSSEnabled, input.CSSEnabled)
if input.Javascript != nil {
c.SetJavascript(*input.Javascript)
}
setBool(config.JavascriptEnabled, input.JavascriptEnabled)
if input.CustomLocales != nil { if input.CustomLocales != nil {
c.SetCustomLocales(*input.CustomLocales) c.SetCustomLocales(*input.CustomLocales)
} }

View File

@ -142,6 +142,8 @@ func makeConfigInterfaceResult() *ConfigInterfaceResult {
showStudioAsText := config.GetShowStudioAsText() showStudioAsText := config.GetShowStudioAsText()
css := config.GetCSS() css := config.GetCSS()
cssEnabled := config.GetCSSEnabled() cssEnabled := config.GetCSSEnabled()
javascript := config.GetJavascript()
javascriptEnabled := config.GetJavascriptEnabled()
customLocales := config.GetCustomLocales() customLocales := config.GetCustomLocales()
customLocalesEnabled := config.GetCustomLocalesEnabled() customLocalesEnabled := config.GetCustomLocalesEnabled()
language := config.GetLanguage() language := config.GetLanguage()
@ -166,6 +168,8 @@ func makeConfigInterfaceResult() *ConfigInterfaceResult {
ContinuePlaylistDefault: &continuePlaylistDefault, ContinuePlaylistDefault: &continuePlaylistDefault,
CSS: &css, CSS: &css,
CSSEnabled: &cssEnabled, CSSEnabled: &cssEnabled,
Javascript: &javascript,
JavascriptEnabled: &javascriptEnabled,
CustomLocales: &customLocales, CustomLocales: &customLocales,
CustomLocalesEnabled: &customLocalesEnabled, CustomLocalesEnabled: &customLocalesEnabled,
Language: &language, Language: &language,

View File

@ -181,6 +181,21 @@ func Start() error {
http.ServeFile(w, r, fn) http.ServeFile(w, r, fn)
}) })
r.HandleFunc("/javascript", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/javascript")
if !c.GetJavascriptEnabled() {
return
}
// search for custom.js in current directory, then $HOME/.stash
fn := c.GetJavascriptPath()
exists, _ := fsutil.FileExists(fn)
if !exists {
return
}
http.ServeFile(w, r, fn)
})
r.HandleFunc("/customlocales", func(w http.ResponseWriter, r *http.Request) { r.HandleFunc("/customlocales", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if c.GetCustomLocalesEnabled() { if c.GetCustomLocalesEnabled() {

View File

@ -139,6 +139,7 @@ const (
ContinuePlaylistDefault = "continue_playlist_default" ContinuePlaylistDefault = "continue_playlist_default"
ShowStudioAsText = "show_studio_as_text" ShowStudioAsText = "show_studio_as_text"
CSSEnabled = "cssEnabled" CSSEnabled = "cssEnabled"
JavascriptEnabled = "javascriptEnabled"
CustomLocalesEnabled = "customLocalesEnabled" CustomLocalesEnabled = "customLocalesEnabled"
ShowScrubber = "show_scrubber" ShowScrubber = "show_scrubber"
@ -1077,6 +1078,49 @@ func (i *Instance) GetCSSEnabled() bool {
return i.getBool(CSSEnabled) return i.getBool(CSSEnabled)
} }
func (i *Instance) GetJavascriptPath() string {
// use custom.js in the same directory as the config file
configFileUsed := i.GetConfigFile()
configDir := filepath.Dir(configFileUsed)
fn := filepath.Join(configDir, "custom.js")
return fn
}
func (i *Instance) GetJavascript() string {
fn := i.GetJavascriptPath()
exists, _ := fsutil.FileExists(fn)
if !exists {
return ""
}
buf, err := os.ReadFile(fn)
if err != nil {
return ""
}
return string(buf)
}
func (i *Instance) SetJavascript(javascript string) {
fn := i.GetJavascriptPath()
i.Lock()
defer i.Unlock()
buf := []byte(javascript)
if err := os.WriteFile(fn, buf, 0777); err != nil {
logger.Warnf("error while writing %v bytes to %v: %v", len(buf), fn, err)
}
}
func (i *Instance) GetJavascriptEnabled() bool {
return i.getBool(JavascriptEnabled)
}
func (i *Instance) GetCustomLocalesPath() string { func (i *Instance) GetCustomLocalesPath() string {
// use custom-locales.json in the same directory as the config file // use custom-locales.json in the same directory as the config file
configFileUsed := i.GetConfigFile() configFileUsed := i.GetConfigFile()

View File

@ -86,6 +86,8 @@ func TestConcurrentConfigAccess(t *testing.T) {
i.Set(ImageLightboxSlideshowDelay, *i.GetImageLightboxOptions().SlideshowDelay) i.Set(ImageLightboxSlideshowDelay, *i.GetImageLightboxOptions().SlideshowDelay)
i.GetCSSPath() i.GetCSSPath()
i.GetCSS() i.GetCSS()
i.GetJavascriptPath()
i.GetJavascript()
i.GetCustomLocalesPath() i.GetCustomLocalesPath()
i.GetCustomLocales() i.GetCustomLocales()
i.Set(CSSEnabled, i.GetCSSEnabled()) i.Set(CSSEnabled, i.GetCSSEnabled())

View File

@ -510,6 +510,36 @@ export const SettingsInterfacePanel: React.FC = () => {
}} }}
/> />
</SettingSection> </SettingSection>
<SettingSection headingID="config.ui.custom_javascript.heading">
<BooleanSetting
id="custom-javascript-enabled"
headingID="config.ui.custom_javascript.option_label"
checked={iface.javascriptEnabled ?? undefined}
onChange={(v) => saveInterface({ javascriptEnabled: v })}
/>
<ModalSetting<string>
id="custom-javascript"
headingID="config.ui.custom_javascript.heading"
subHeadingID="config.ui.custom_javascript.description"
value={iface.javascript ?? undefined}
onChange={(v) => saveInterface({ javascript: v })}
renderField={(value, setValue) => (
<Form.Control
as="textarea"
value={value}
onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) =>
setValue(e.currentTarget.value)
}
rows={16}
className="text-input code"
/>
)}
renderValue={() => {
return <></>;
}}
/>
</SettingSection>
<SettingSection headingID="config.ui.custom_locales.heading"> <SettingSection headingID="config.ui.custom_locales.heading">
<BooleanSetting <BooleanSetting
id="custom-locales-enabled" id="custom-locales-enabled"

View File

@ -1,4 +1,5 @@
### ✨ New Features ### ✨ New Features
* Added custom javascript option. ([#3132](https://github.com/stashapp/stash/pull/3132))
* Added ability to select rating system in the Interface settings, allowing 5 stars with full-, half- or quarter-stars, or numeric score out of 10 with one decimal point. ([#2830](https://github.com/stashapp/stash/pull/2830)) * Added ability to select rating system in the Interface settings, allowing 5 stars with full-, half- or quarter-stars, or numeric score out of 10 with one decimal point. ([#2830](https://github.com/stashapp/stash/pull/2830))
* Added filter criteria for Birthdate, Death Date, Date, Created At and Updated At fields. ([#2834](https://github.com/stashapp/stash/pull/2834)) * Added filter criteria for Birthdate, Death Date, Date, Created At and Updated At fields. ([#2834](https://github.com/stashapp/stash/pull/2834))
* Support creation of scenes without files. ([#3006](https://github.com/stashapp/stash/pull/3006)) * Support creation of scenes without files. ([#3006](https://github.com/stashapp/stash/pull/3006))

View File

@ -26,6 +26,10 @@ The stash UI can be customised using custom CSS. See [here](https://github.com/s
[Stash Plex Theme](https://github.com/stashapp/stash/wiki/Theme-Plex) is a community created theme inspired by the popular Plex interface. [Stash Plex Theme](https://github.com/stashapp/stash/wiki/Theme-Plex) is a community created theme inspired by the popular Plex interface.
## Custom Javascript
Stash supports the injection of custom javascript to assist with theming or adding additional functionality. Be aware that bad Javascript could break the UI or worse.
## Custom Locales ## Custom Locales
The localisation strings can be customised. The master list of default (en-GB) locale strings can be found [here](https://github.com/stashapp/stash/blob/develop/ui/v2.5/src/locales/en-GB.json). The custom locale format is the same as this json file. The localisation strings can be customised. The master list of default (en-GB) locale strings can be found [here](https://github.com/stashapp/stash/blob/develop/ui/v2.5/src/locales/en-GB.json). The custom locale format is the same as this json file.

View File

@ -20,6 +20,10 @@ ReactDOM.render(
document.getElementById("root") document.getElementById("root")
); );
const script = document.createElement("script");
script.src = `${getPlatformURL()}javascript`;
document.body.appendChild(script);
// If you want your app to work offline and load faster, you can change // If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls. // unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: http://bit.ly/CRA-PWA // Learn more about service workers: http://bit.ly/CRA-PWA

View File

@ -435,6 +435,11 @@
"heading": "Custom CSS", "heading": "Custom CSS",
"option_label": "Custom CSS enabled" "option_label": "Custom CSS enabled"
}, },
"custom_javascript": {
"description": "Page must be reloaded for changes to take effect.",
"heading": "Custom Javascript",
"option_label": "Custom Javascript enabled"
},
"custom_locales": { "custom_locales": {
"description": "Override individual locale strings. See https://github.com/stashapp/stash/blob/develop/ui/v2.5/src/locales/en-GB.json for the master list. Page must be reloaded for changes to take effect.", "description": "Override individual locale strings. See https://github.com/stashapp/stash/blob/develop/ui/v2.5/src/locales/en-GB.json for the master list. Page must be reloaded for changes to take effect.",
"heading": "Custom localisation", "heading": "Custom localisation",