mirror of
https://github.com/p-stream/p-stream.git
synced 2026-03-11 17:55:33 +00:00
add setting to disable speed boost
This commit is contained in:
parent
e79a04c204
commit
b34e263369
9 changed files with 101 additions and 9 deletions
|
|
@ -1027,6 +1027,9 @@
|
|||
"lowPerformanceMode": "Low performance/bandwidth mode",
|
||||
"lowPerformanceModeDescription": "Optimizes the application for slower connections and devices by disabling bandwidth-heavy features. This mode reduces data usage and improves performance while keeping the core search and watch functionality intact. ",
|
||||
"lowPerformanceModeLabel": "Low performance mode",
|
||||
"holdToBoost": "Hold to boost speed",
|
||||
"holdToBoostDescription": "Hold spacebar or touch and hold the screen to temporarily increase playback speed to 2x. Release to return to previous speed.",
|
||||
"holdToBoostLabel": "Enable hold to boost",
|
||||
"sourceOrder": "Reordering sources",
|
||||
"sourceOrderDescription": "Drag and drop to reorder sources. This will determine the order in which sources are checked for the media you are trying to watch. If a source is greyed out, it means the <bold>extension</bold> is required for that source. <br><br> <strong>(The default order is best for most users)</strong>",
|
||||
"sourceOrderEnableLabel": "Custom source order",
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ export interface SettingsInput {
|
|||
proxyTmdb?: boolean;
|
||||
enableLowPerformanceMode?: boolean;
|
||||
enableNativeSubtitles?: boolean;
|
||||
enableHoldToBoost?: boolean;
|
||||
}
|
||||
|
||||
export interface SettingsResponse {
|
||||
|
|
@ -50,6 +51,7 @@ export interface SettingsResponse {
|
|||
proxyTmdb?: boolean;
|
||||
enableLowPerformanceMode?: boolean;
|
||||
enableNativeSubtitles?: boolean;
|
||||
enableHoldToBoost?: boolean;
|
||||
}
|
||||
|
||||
export function updateSettings(
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { useVolume } from "@/components/player/hooks/useVolume";
|
|||
import { useOverlayRouter } from "@/hooks/useOverlayRouter";
|
||||
import { useOverlayStack } from "@/stores/interface/overlayStack";
|
||||
import { usePlayerStore } from "@/stores/player/store";
|
||||
import { usePreferencesStore } from "@/stores/preferences";
|
||||
import { useSubtitleStore } from "@/stores/subtitles";
|
||||
import { useEmpheralVolumeStore } from "@/stores/volume";
|
||||
import { useWatchPartyStore } from "@/stores/watchParty";
|
||||
|
|
@ -26,6 +27,7 @@ export function KeyboardEvents() {
|
|||
const setShowDelayIndicator = useSubtitleStore(
|
||||
(s) => s.setShowDelayIndicator,
|
||||
);
|
||||
const enableHoldToBoost = usePreferencesStore((s) => s.enableHoldToBoost);
|
||||
|
||||
const [isRolling, setIsRolling] = useState(false);
|
||||
const volumeDebounce = useRef<ReturnType<typeof setTimeout> | undefined>();
|
||||
|
|
@ -69,6 +71,7 @@ export function KeyboardEvents() {
|
|||
speedIndicatorTimeoutRef,
|
||||
boostTimeoutRef,
|
||||
isPendingBoostRef,
|
||||
enableHoldToBoost,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -97,6 +100,7 @@ export function KeyboardEvents() {
|
|||
speedIndicatorTimeoutRef,
|
||||
boostTimeoutRef,
|
||||
isPendingBoostRef,
|
||||
enableHoldToBoost,
|
||||
};
|
||||
}, [
|
||||
setShowVolume,
|
||||
|
|
@ -118,6 +122,7 @@ export function KeyboardEvents() {
|
|||
isInWatchParty,
|
||||
setSpeedBoosted,
|
||||
setShowSpeedIndicator,
|
||||
enableHoldToBoost,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -159,8 +164,12 @@ export function KeyboardEvents() {
|
|||
if (next) dataRef.current.display?.setPlaybackRate(next);
|
||||
}
|
||||
|
||||
// Handle spacebar press for play/pause and hold for 2x speed - disabled in watch party
|
||||
if (k === " " && !dataRef.current.isInWatchParty) {
|
||||
// Handle spacebar press for play/pause and hold for 2x speed - disabled in watch party or when hold to boost is disabled
|
||||
if (
|
||||
k === " " &&
|
||||
!dataRef.current.isInWatchParty &&
|
||||
dataRef.current.enableHoldToBoost
|
||||
) {
|
||||
// Skip if a button is targeted
|
||||
if (
|
||||
evt.target &&
|
||||
|
|
@ -216,8 +225,11 @@ export function KeyboardEvents() {
|
|||
}, 300); // 300ms delay before boost takes effect
|
||||
}
|
||||
|
||||
// Handle spacebar press for play/pause only in watch party mode
|
||||
if (k === " " && dataRef.current.isInWatchParty) {
|
||||
// Handle spacebar press for simple play/pause when hold to boost is disabled or in watch party mode
|
||||
if (
|
||||
k === " " &&
|
||||
(!dataRef.current.enableHoldToBoost || dataRef.current.isInWatchParty)
|
||||
) {
|
||||
// Skip if a button is targeted
|
||||
if (
|
||||
evt.target &&
|
||||
|
|
@ -302,8 +314,12 @@ export function KeyboardEvents() {
|
|||
const keyupEventHandler = (evt: KeyboardEvent) => {
|
||||
const k = evt.key;
|
||||
|
||||
// Handle spacebar release - only handle speed boost logic when not in watch party
|
||||
if (k === " " && !dataRef.current.isInWatchParty) {
|
||||
// Handle spacebar release - only handle speed boost logic when not in watch party and hold to boost is enabled
|
||||
if (
|
||||
k === " " &&
|
||||
!dataRef.current.isInWatchParty &&
|
||||
dataRef.current.enableHoldToBoost
|
||||
) {
|
||||
// If we haven't applied the boost yet but were about to, cancel it
|
||||
if (dataRef.current.isPendingBoostRef.current) {
|
||||
dataRef.current.isPendingBoostRef.current = false;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { useShouldShowVideoElement } from "@/components/player/internals/VideoCo
|
|||
import { useOverlayStack } from "@/stores/interface/overlayStack";
|
||||
import { PlayerHoverState } from "@/stores/player/slices/interface";
|
||||
import { usePlayerStore } from "@/stores/player/store";
|
||||
import { usePreferencesStore } from "@/stores/preferences";
|
||||
import { useWatchPartyStore } from "@/stores/watchParty";
|
||||
|
||||
export function VideoClickTarget(props: { showingControls: boolean }) {
|
||||
|
|
@ -21,6 +22,7 @@ export function VideoClickTarget(props: { showingControls: boolean }) {
|
|||
const hovering = usePlayerStore((s) => s.interface.hovering);
|
||||
const setCurrentOverlay = useOverlayStack((s) => s.setCurrentOverlay);
|
||||
const isInWatchParty = useWatchPartyStore((s) => s.enabled);
|
||||
const enableHoldToBoost = usePreferencesStore((s) => s.enableHoldToBoost);
|
||||
|
||||
const [_, cancel, reset] = useTimeoutFn(() => {
|
||||
updateInterfaceHovering(PlayerHoverState.NOT_HOVERING);
|
||||
|
|
@ -87,7 +89,8 @@ export function VideoClickTarget(props: { showingControls: boolean }) {
|
|||
if (
|
||||
((e.pointerType === "mouse" && e.button === 0) ||
|
||||
e.pointerType === "touch") &&
|
||||
!isInWatchParty
|
||||
!isInWatchParty &&
|
||||
enableHoldToBoost
|
||||
) {
|
||||
if (isPaused) return; // Don't boost if video is paused
|
||||
|
||||
|
|
@ -128,6 +131,7 @@ export function VideoClickTarget(props: { showingControls: boolean }) {
|
|||
setShowSpeedIndicator,
|
||||
setCurrentOverlay,
|
||||
isInWatchParty,
|
||||
enableHoldToBoost,
|
||||
],
|
||||
);
|
||||
|
||||
|
|
@ -143,6 +147,7 @@ export function VideoClickTarget(props: { showingControls: boolean }) {
|
|||
|
||||
if (
|
||||
isHoldingRef.current &&
|
||||
enableHoldToBoost &&
|
||||
((e.pointerType === "mouse" && e.button === 0) ||
|
||||
e.pointerType === "touch")
|
||||
) {
|
||||
|
|
@ -175,6 +180,7 @@ export function VideoClickTarget(props: { showingControls: boolean }) {
|
|||
setShowSpeedIndicator,
|
||||
setCurrentOverlay,
|
||||
isPendingBoost,
|
||||
enableHoldToBoost,
|
||||
],
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -62,6 +62,9 @@ export function useAuthData() {
|
|||
const setEnableNativeSubtitles = usePreferencesStore(
|
||||
(s) => s.setEnableNativeSubtitles,
|
||||
);
|
||||
const setEnableHoldToBoost = usePreferencesStore(
|
||||
(s) => s.setEnableHoldToBoost,
|
||||
);
|
||||
|
||||
const login = useCallback(
|
||||
async (
|
||||
|
|
@ -185,6 +188,10 @@ export function useAuthData() {
|
|||
if (settings.enableNativeSubtitles !== undefined) {
|
||||
setEnableNativeSubtitles(settings.enableNativeSubtitles);
|
||||
}
|
||||
|
||||
if (settings.enableHoldToBoost !== undefined) {
|
||||
setEnableHoldToBoost(settings.enableHoldToBoost);
|
||||
}
|
||||
},
|
||||
[
|
||||
replaceBookmarks,
|
||||
|
|
@ -207,6 +214,7 @@ export function useAuthData() {
|
|||
setFebboxKey,
|
||||
setEnableLowPerformanceMode,
|
||||
setEnableNativeSubtitles,
|
||||
setEnableHoldToBoost,
|
||||
],
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ export function useSettingsState(
|
|||
enableCarouselView: boolean,
|
||||
forceCompactEpisodeView: boolean,
|
||||
enableLowPerformanceMode: boolean,
|
||||
enableHoldToBoost: boolean,
|
||||
) {
|
||||
const [proxyUrlsState, setProxyUrls, resetProxyUrls, proxyUrlsChanged] =
|
||||
useDerived(proxyUrls);
|
||||
|
|
@ -174,6 +175,12 @@ export function useSettingsState(
|
|||
resetEnableLowPerformanceMode,
|
||||
enableLowPerformanceModeChanged,
|
||||
] = useDerived(enableLowPerformanceMode);
|
||||
const [
|
||||
enableHoldToBoostState,
|
||||
setEnableHoldToBoostState,
|
||||
resetEnableHoldToBoost,
|
||||
enableHoldToBoostChanged,
|
||||
] = useDerived(enableHoldToBoost);
|
||||
|
||||
function reset() {
|
||||
resetTheme();
|
||||
|
|
@ -199,6 +206,7 @@ export function useSettingsState(
|
|||
resetEnableCarouselView();
|
||||
resetForceCompactEpisodeView();
|
||||
resetEnableLowPerformanceMode();
|
||||
resetEnableHoldToBoost();
|
||||
}
|
||||
|
||||
const changed =
|
||||
|
|
@ -223,7 +231,8 @@ export function useSettingsState(
|
|||
proxyTmdbChanged ||
|
||||
enableCarouselViewChanged ||
|
||||
forceCompactEpisodeViewChanged ||
|
||||
enableLowPerformanceModeChanged;
|
||||
enableLowPerformanceModeChanged ||
|
||||
enableHoldToBoostChanged;
|
||||
|
||||
return {
|
||||
reset,
|
||||
|
|
@ -338,5 +347,10 @@ export function useSettingsState(
|
|||
set: setEnableLowPerformanceModeState,
|
||||
changed: enableLowPerformanceModeChanged,
|
||||
},
|
||||
enableHoldToBoost: {
|
||||
state: enableHoldToBoostState,
|
||||
set: setEnableHoldToBoostState,
|
||||
changed: enableHoldToBoostChanged,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -192,6 +192,11 @@ export function SettingsPage() {
|
|||
(s) => s.setEnableLowPerformanceMode,
|
||||
);
|
||||
|
||||
const enableHoldToBoost = usePreferencesStore((s) => s.enableHoldToBoost);
|
||||
const setEnableHoldToBoost = usePreferencesStore(
|
||||
(s) => s.setEnableHoldToBoost,
|
||||
);
|
||||
|
||||
const account = useAuthStore((s) => s.account);
|
||||
const updateProfile = useAuthStore((s) => s.setAccountProfile);
|
||||
const updateDeviceName = useAuthStore((s) => s.updateDeviceName);
|
||||
|
|
@ -243,6 +248,7 @@ export function SettingsPage() {
|
|||
enableCarouselView,
|
||||
forceCompactEpisodeView,
|
||||
enableLowPerformanceMode,
|
||||
enableHoldToBoost,
|
||||
);
|
||||
|
||||
const availableSources = useMemo(() => {
|
||||
|
|
@ -300,7 +306,8 @@ export function SettingsPage() {
|
|||
state.proxyTmdb.changed ||
|
||||
state.enableCarouselView.changed ||
|
||||
state.forceCompactEpisodeView.changed ||
|
||||
state.enableLowPerformanceMode.changed
|
||||
state.enableLowPerformanceMode.changed ||
|
||||
state.enableHoldToBoost.changed
|
||||
) {
|
||||
await updateSettings(backendUrl, account, {
|
||||
applicationLanguage: state.appLanguage.state,
|
||||
|
|
@ -321,6 +328,7 @@ export function SettingsPage() {
|
|||
enableCarouselView: state.enableCarouselView.state,
|
||||
forceCompactEpisodeView: state.forceCompactEpisodeView.state,
|
||||
enableLowPerformanceMode: state.enableLowPerformanceMode.state,
|
||||
enableHoldToBoost: state.enableHoldToBoost.state,
|
||||
});
|
||||
}
|
||||
if (state.deviceName.changed) {
|
||||
|
|
@ -360,6 +368,7 @@ export function SettingsPage() {
|
|||
setEnableCarouselView(state.enableCarouselView.state);
|
||||
setForceCompactEpisodeView(state.forceCompactEpisodeView.state);
|
||||
setEnableLowPerformanceMode(state.enableLowPerformanceMode.state);
|
||||
setEnableHoldToBoost(state.enableHoldToBoost.state);
|
||||
|
||||
if (state.profile.state) {
|
||||
updateProfile(state.profile.state);
|
||||
|
|
@ -403,6 +412,7 @@ export function SettingsPage() {
|
|||
setEnableCarouselView,
|
||||
setForceCompactEpisodeView,
|
||||
setEnableLowPerformanceMode,
|
||||
setEnableHoldToBoost,
|
||||
]);
|
||||
return (
|
||||
<SubPageLayout>
|
||||
|
|
@ -453,6 +463,8 @@ export function SettingsPage() {
|
|||
setenableSourceOrder={state.enableSourceOrder.set}
|
||||
enableLowPerformanceMode={state.enableLowPerformanceMode.state}
|
||||
setEnableLowPerformanceMode={state.enableLowPerformanceMode.set}
|
||||
enableHoldToBoost={state.enableHoldToBoost.state}
|
||||
setEnableHoldToBoost={state.enableHoldToBoost.set}
|
||||
/>
|
||||
</div>
|
||||
<div id="settings-appearance" className="mt-28">
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ export function PreferencesPart(props: {
|
|||
setenableSourceOrder: (v: boolean) => void;
|
||||
enableLowPerformanceMode: boolean;
|
||||
setEnableLowPerformanceMode: (v: boolean) => void;
|
||||
enableHoldToBoost: boolean;
|
||||
setEnableHoldToBoost: (v: boolean) => void;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const sorted = sortLangCodes(appLanguageOptions.map((item) => item.code));
|
||||
|
|
@ -191,6 +193,27 @@ export function PreferencesPart(props: {
|
|||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Hold to Boost Preference */}
|
||||
<div>
|
||||
<p className="text-white font-bold mb-3">
|
||||
{t("settings.preferences.holdToBoost")}
|
||||
</p>
|
||||
<p className="max-w-[25rem] font-medium">
|
||||
{t("settings.preferences.holdToBoostDescription")}
|
||||
</p>
|
||||
<div
|
||||
onClick={() =>
|
||||
props.setEnableHoldToBoost(!props.enableHoldToBoost)
|
||||
}
|
||||
className="bg-dropdown-background hover:bg-dropdown-hoverBackground select-none my-4 cursor-pointer space-x-3 flex items-center max-w-[25rem] py-3 px-4 rounded-lg"
|
||||
>
|
||||
<Toggle enabled={props.enableHoldToBoost} />
|
||||
<p className="flex-1 text-white font-bold">
|
||||
{t("settings.preferences.holdToBoostLabel")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Column */}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ export interface PreferencesStore {
|
|||
realDebridKey: string | null;
|
||||
enableLowPerformanceMode: boolean;
|
||||
enableNativeSubtitles: boolean;
|
||||
enableHoldToBoost: boolean;
|
||||
|
||||
setEnableThumbnails(v: boolean): void;
|
||||
setEnableAutoplay(v: boolean): void;
|
||||
|
|
@ -40,6 +41,7 @@ export interface PreferencesStore {
|
|||
setRealDebridKey(v: string | null): void;
|
||||
setEnableLowPerformanceMode(v: boolean): void;
|
||||
setEnableNativeSubtitles(v: boolean): void;
|
||||
setEnableHoldToBoost(v: boolean): void;
|
||||
}
|
||||
|
||||
export const usePreferencesStore = create(
|
||||
|
|
@ -63,6 +65,7 @@ export const usePreferencesStore = create(
|
|||
realDebridKey: null,
|
||||
enableLowPerformanceMode: false,
|
||||
enableNativeSubtitles: false,
|
||||
enableHoldToBoost: true,
|
||||
setEnableThumbnails(v) {
|
||||
set((s) => {
|
||||
s.enableThumbnails = v;
|
||||
|
|
@ -153,6 +156,11 @@ export const usePreferencesStore = create(
|
|||
s.enableNativeSubtitles = v;
|
||||
});
|
||||
},
|
||||
setEnableHoldToBoost(v) {
|
||||
set((s) => {
|
||||
s.enableHoldToBoost = v;
|
||||
});
|
||||
},
|
||||
})),
|
||||
{
|
||||
name: "__MW::preferences",
|
||||
|
|
|
|||
Loading…
Reference in a new issue