mirror of https://github.com/stashapp/stash.git
Add script offset / delay to Handy support. (#1573)
* Add script offset / delay to Handy support. Further work on #1376. Offsets are added to the current video position, so a positive value leads to earlier motion. (The most common setting.) This is needed because most script times have a consistent delay when compared to the video. (Delay from the API calls to the server should be handled by the server offset calculation.) * Rename scriptOffset to funscriptOffset * Correct localisation keys Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
This commit is contained in:
parent
50217f6318
commit
45a9aabdaf
|
@ -56,6 +56,7 @@ fragment ConfigInterfaceData on ConfigInterfaceResult {
|
|||
language
|
||||
slideshowDelay
|
||||
handyKey
|
||||
funscriptOffset
|
||||
}
|
||||
|
||||
fragment ConfigDLNAData on ConfigDLNAResult {
|
||||
|
|
|
@ -200,6 +200,8 @@ input ConfigInterfaceInput {
|
|||
slideshowDelay: Int
|
||||
"""Handy Connection Key"""
|
||||
handyKey: String
|
||||
"""Funscript Time Offset"""
|
||||
funscriptOffset: Int
|
||||
}
|
||||
|
||||
type ConfigInterfaceResult {
|
||||
|
@ -226,6 +228,8 @@ type ConfigInterfaceResult {
|
|||
slideshowDelay: Int
|
||||
"""Handy Connection Key"""
|
||||
handyKey: String
|
||||
"""Funscript Time Offset"""
|
||||
funscriptOffset: Int
|
||||
}
|
||||
|
||||
input ConfigDLNAInput {
|
||||
|
|
|
@ -260,6 +260,10 @@ func (r *mutationResolver) ConfigureInterface(ctx context.Context, input models.
|
|||
c.Set(config.HandyKey, *input.HandyKey)
|
||||
}
|
||||
|
||||
if input.FunscriptOffset != nil {
|
||||
c.Set(config.FunscriptOffset, *input.FunscriptOffset)
|
||||
}
|
||||
|
||||
if err := c.Write(); err != nil {
|
||||
return makeConfigInterfaceResult(), err
|
||||
}
|
||||
|
|
|
@ -109,6 +109,7 @@ func makeConfigInterfaceResult() *models.ConfigInterfaceResult {
|
|||
language := config.GetLanguage()
|
||||
slideshowDelay := config.GetSlideshowDelay()
|
||||
handyKey := config.GetHandyKey()
|
||||
scriptOffset := config.GetFunscriptOffset()
|
||||
|
||||
return &models.ConfigInterfaceResult{
|
||||
MenuItems: menuItems,
|
||||
|
@ -123,6 +124,7 @@ func makeConfigInterfaceResult() *models.ConfigInterfaceResult {
|
|||
Language: &language,
|
||||
SlideshowDelay: &slideshowDelay,
|
||||
HandyKey: &handyKey,
|
||||
FunscriptOffset: &scriptOffset,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -132,6 +132,7 @@ const CSSEnabled = "cssEnabled"
|
|||
const WallPlayback = "wall_playback"
|
||||
const SlideshowDelay = "slideshow_delay"
|
||||
const HandyKey = "handy_key"
|
||||
const FunscriptOffset = "funscript_offset"
|
||||
|
||||
// DLNA options
|
||||
const DLNAServerName = "dlna.server_name"
|
||||
|
@ -798,6 +799,11 @@ func (i *Instance) GetHandyKey() string {
|
|||
return viper.GetString(HandyKey)
|
||||
}
|
||||
|
||||
func (i *Instance) GetFunscriptOffset() int {
|
||||
viper.SetDefault(FunscriptOffset, 0)
|
||||
return viper.GetInt(FunscriptOffset)
|
||||
}
|
||||
|
||||
// GetDLNAServerName returns the visible name of the DLNA server. If empty,
|
||||
// "stash" will be used.
|
||||
func (i *Instance) GetDLNAServerName() string {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
### ✨ New Features
|
||||
* Support setting a fixed funscript offset/delay. ([#1573](https://github.com/stashapp/stash/pull/1573))
|
||||
* Added sort by options for image and gallery count for performers. ([#1671](https://github.com/stashapp/stash/pull/1671))
|
||||
* Added sort by options for date, duration and rating for movies. ([#1663](https://github.com/stashapp/stash/pull/1663))
|
||||
* Allow saving query page zoom level in saved and default filters. ([#1636](https://github.com/stashapp/stash/pull/1636))
|
||||
|
@ -12,7 +13,7 @@
|
|||
|
||||
### 🎨 Improvements
|
||||
* Move Play Selected Scenes, and Add/Remove Gallery Image buttons to button toolbar. ([#1673](https://github.com/stashapp/stash/pull/1673))
|
||||
* Add image and gallery counts to tag list view. ([#1672](https://github.com/stashapp/stash/pull/1672))
|
||||
* Added image and gallery counts to tag list view. ([#1672](https://github.com/stashapp/stash/pull/1672))
|
||||
* Prompt when leaving gallery and image edit pages with unsaved changes. ([#1654](https://github.com/stashapp/stash/pull/1654), [#1669](https://github.com/stashapp/stash/pull/1669))
|
||||
* Show largest duplicates first in scene duplicate checker. ([#1639](https://github.com/stashapp/stash/pull/1639))
|
||||
* Added checkboxes to scene list view. ([#1642](https://github.com/stashapp/stash/pull/1642))
|
||||
|
|
|
@ -54,7 +54,10 @@ export class ScenePlayerImpl extends React.Component<
|
|||
this.state = {
|
||||
scrubberPosition: 0,
|
||||
config: this.makeJWPlayerConfig(props.scene),
|
||||
interactiveClient: new Interactive(this.props.config?.handyKey || ""),
|
||||
interactiveClient: new Interactive(
|
||||
this.props.config?.handyKey || "",
|
||||
this.props.config?.funscriptOffset || 0
|
||||
),
|
||||
};
|
||||
|
||||
// Default back to Direct Streaming
|
||||
|
|
|
@ -37,6 +37,7 @@ export const SettingsInterfacePanel: React.FC = () => {
|
|||
const [cssEnabled, setCSSEnabled] = useState<boolean>(false);
|
||||
const [language, setLanguage] = useState<string>("en");
|
||||
const [handyKey, setHandyKey] = useState<string>();
|
||||
const [funscriptOffset, setFunscriptOffset] = useState<number>(0);
|
||||
|
||||
const [updateInterfaceConfig] = useConfigureInterface({
|
||||
menuItems: menuItemIds,
|
||||
|
@ -51,6 +52,7 @@ export const SettingsInterfacePanel: React.FC = () => {
|
|||
language,
|
||||
slideshowDelay,
|
||||
handyKey,
|
||||
funscriptOffset,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -67,6 +69,7 @@ export const SettingsInterfacePanel: React.FC = () => {
|
|||
setLanguage(iCfg?.language ?? "en-US");
|
||||
setSlideshowDelay(iCfg?.slideshowDelay ?? 5000);
|
||||
setHandyKey(iCfg?.handyKey ?? "");
|
||||
setFunscriptOffset(iCfg?.funscriptOffset ?? 0);
|
||||
}, [config]);
|
||||
|
||||
async function onSave() {
|
||||
|
@ -281,7 +284,9 @@ export const SettingsInterfacePanel: React.FC = () => {
|
|||
</Form.Group>
|
||||
|
||||
<Form.Group>
|
||||
<h5>{intl.formatMessage({ id: "config.ui.handy_connection_key" })}</h5>
|
||||
<h5>
|
||||
{intl.formatMessage({ id: "config.ui.handy_connection_key.heading" })}
|
||||
</h5>
|
||||
<Form.Control
|
||||
className="col col-sm-6 text-input"
|
||||
value={handyKey}
|
||||
|
@ -290,7 +295,25 @@ export const SettingsInterfacePanel: React.FC = () => {
|
|||
}}
|
||||
/>
|
||||
<Form.Text className="text-muted">
|
||||
{intl.formatMessage({ id: "config.ui.handy_connection_key_desc" })}
|
||||
{intl.formatMessage({
|
||||
id: "config.ui.handy_connection_key.description",
|
||||
})}
|
||||
</Form.Text>
|
||||
</Form.Group>
|
||||
<Form.Group>
|
||||
<h5>
|
||||
{intl.formatMessage({ id: "config.ui.funscript_offset.heading" })}
|
||||
</h5>
|
||||
<Form.Control
|
||||
className="col col-sm-6 text-input"
|
||||
type="number"
|
||||
value={funscriptOffset}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setFunscriptOffset(Number.parseInt(e.currentTarget.value, 10));
|
||||
}}
|
||||
/>
|
||||
<Form.Text className="text-muted">
|
||||
{intl.formatMessage({ id: "config.ui.funscript_offset.description" })}
|
||||
</Form.Text>
|
||||
</Form.Group>
|
||||
|
||||
|
|
|
@ -308,8 +308,10 @@
|
|||
"heading": "Benutzerdefinierte CSS",
|
||||
"option_label": "Benutzerdefiniertes CSS aktiviert"
|
||||
},
|
||||
"handy_connection_key": "Handy Verbindungsschlüssel",
|
||||
"handy_connection_key_desc": "Handy Verbindungsschlüssel für interaktive Szenen.",
|
||||
"handy_connection_key": {
|
||||
"description": "Handy Verbindungsschlüssel für interaktive Szenen.",
|
||||
"heading": "Handy Verbindungsschlüssel"
|
||||
},
|
||||
"language": {
|
||||
"heading": "Sprache"
|
||||
},
|
||||
|
|
|
@ -315,8 +315,14 @@
|
|||
"heading": "Custom CSS",
|
||||
"option_label": "Custom CSS enabled"
|
||||
},
|
||||
"handy_connection_key": "Handy Connection Key",
|
||||
"handy_connection_key_desc": "Handy connection key to use for interactive scenes.",
|
||||
"handy_connection_key": {
|
||||
"description": "Handy connection key to use for interactive scenes.",
|
||||
"heading": "Handy Connection Key"
|
||||
},
|
||||
"funscript_offset": {
|
||||
"description": "Time offset in milliseconds for interactive scripts playback.",
|
||||
"heading": "Funscript Offset (ms)"
|
||||
},
|
||||
"language": {
|
||||
"heading": "Language"
|
||||
},
|
||||
|
|
|
@ -308,8 +308,10 @@
|
|||
"heading": "CSS customizado",
|
||||
"option_label": "CSS customizado habilitado"
|
||||
},
|
||||
"handy_connection_key": "Chave de conexão",
|
||||
"handy_connection_key_desc": "Chave de conexão para usar em cenas interativas.",
|
||||
"handy_connection_key": {
|
||||
"description": "Chave de conexão para usar em cenas interativas.",
|
||||
"heading": "Chave de conexão"
|
||||
},
|
||||
"language": {
|
||||
"heading": "Idioma"
|
||||
},
|
||||
|
|
|
@ -308,8 +308,10 @@
|
|||
"heading": "自定义样式",
|
||||
"option_label": "自定义样式已启用"
|
||||
},
|
||||
"handy_connection_key": "快速连接密钥",
|
||||
"handy_connection_key_desc": "用于互动场景的快速连接密钥",
|
||||
"handy_connection_key": {
|
||||
"description": "用于互动场景的快速连接密钥",
|
||||
"heading": "快速连接密钥"
|
||||
},
|
||||
"language": {
|
||||
"heading": "语言"
|
||||
},
|
||||
|
|
|
@ -310,8 +310,10 @@
|
|||
"heading": "自定義 CSS",
|
||||
"option_label": "啟用自定義 CSS"
|
||||
},
|
||||
"handy_connection_key": "Handy 連線金鑰",
|
||||
"handy_connection_key_desc": "播放支援互動性的短片時所用的 Handy 連線金鑰。",
|
||||
"handy_connection_key": {
|
||||
"description": "播放支援互動性的短片時所用的 Handy 連線金鑰。",
|
||||
"heading": "Handy 連線金鑰"
|
||||
},
|
||||
"language": {
|
||||
"heading": "語言"
|
||||
},
|
||||
|
|
|
@ -26,11 +26,13 @@ function convertFunscriptToCSV(funscript: IFunscript) {
|
|||
export class Interactive {
|
||||
private _connected: boolean;
|
||||
private _playing: boolean;
|
||||
private _scriptOffset: number;
|
||||
private _handy: Handy;
|
||||
|
||||
constructor(handyKey: string) {
|
||||
constructor(handyKey: string, scriptOffset: number) {
|
||||
this._handy = new Handy();
|
||||
this._handy.connectionKey = handyKey;
|
||||
this._scriptOffset = scriptOffset;
|
||||
this._connected = false;
|
||||
this._playing = false;
|
||||
}
|
||||
|
@ -76,7 +78,7 @@ export class Interactive {
|
|||
return;
|
||||
}
|
||||
this._playing = await this._handy
|
||||
.syncPlay(true, Math.round(position * 1000))
|
||||
.syncPlay(true, Math.round(position * 1000 + this._scriptOffset))
|
||||
.then(() => true);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue