mirror of
https://github.com/p-stream/p-stream.git
synced 2026-03-29 00:58:42 +00:00
fix playbacksettingsview settigns not working correctly
didnt save to backend or apply thumbails. Also hid them when performance mode is enabled
This commit is contained in:
parent
71a3d91b2a
commit
55b68c520e
5 changed files with 91 additions and 28 deletions
|
|
@ -1,13 +1,19 @@
|
|||
import classNames from "classnames";
|
||||
|
||||
export function Toggle(props: { onClick?: () => void; enabled?: boolean }) {
|
||||
export function Toggle(props: {
|
||||
onClick?: () => void;
|
||||
enabled?: boolean;
|
||||
disabled?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
onClick={props.onClick}
|
||||
onClick={props.disabled ? undefined : props.onClick}
|
||||
disabled={props.disabled}
|
||||
className={classNames(
|
||||
"w-11 h-6 p-1 rounded-full grid transition-colors duration-100 group/toggle tabbable",
|
||||
props.enabled ? "bg-buttons-toggle" : "bg-buttons-toggleDisabled",
|
||||
props.disabled ? "opacity-50 cursor-not-allowed" : null,
|
||||
)}
|
||||
>
|
||||
<div className="relative w-full h-full">
|
||||
|
|
|
|||
|
|
@ -2,10 +2,13 @@ import classNames from "classnames";
|
|||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { updateSettings } from "@/backend/accounts/settings";
|
||||
import { Toggle } from "@/components/buttons/Toggle";
|
||||
import { Icon, Icons } from "@/components/Icon";
|
||||
import { Menu } from "@/components/player/internals/ContextMenu";
|
||||
import { useBackendUrl } from "@/hooks/auth/useBackendUrl";
|
||||
import { useOverlayRouter } from "@/hooks/useOverlayRouter";
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
import { usePlayerStore } from "@/stores/player/store";
|
||||
import { usePreferencesStore } from "@/stores/preferences";
|
||||
import { useWatchPartyStore } from "@/stores/watchParty";
|
||||
|
|
@ -188,10 +191,43 @@ export function PlaybackSettingsView({ id }: { id: string }) {
|
|||
);
|
||||
const isInWatchParty = useWatchPartyStore((s) => s.enabled);
|
||||
|
||||
const account = useAuthStore((s) => s.account);
|
||||
const backendUrl = useBackendUrl();
|
||||
const allowAutoplay = useMemo(() => isAutoplayAllowed(), []);
|
||||
const canShowAutoplay =
|
||||
!isInWatchParty && allowAutoplay && !enableLowPerformanceMode;
|
||||
|
||||
// Save settings to backend
|
||||
const saveThumbnailSetting = useCallback(
|
||||
async (value: boolean) => {
|
||||
if (!account || !backendUrl) return;
|
||||
|
||||
try {
|
||||
await updateSettings(backendUrl, account, {
|
||||
enableThumbnails: value,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Failed to save thumbnail setting:", error);
|
||||
}
|
||||
},
|
||||
[account, backendUrl],
|
||||
);
|
||||
|
||||
const saveAutoplaySetting = useCallback(
|
||||
async (value: boolean) => {
|
||||
if (!account || !backendUrl) return;
|
||||
|
||||
try {
|
||||
await updateSettings(backendUrl, account, {
|
||||
enableAutoplay: value,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Failed to save autoplay setting:", error);
|
||||
}
|
||||
},
|
||||
[account, backendUrl],
|
||||
);
|
||||
|
||||
const setPlaybackRate = useCallback(
|
||||
(v: number) => {
|
||||
if (isInWatchParty) return; // Don't allow changes in watch party
|
||||
|
|
@ -200,6 +236,20 @@ export function PlaybackSettingsView({ id }: { id: string }) {
|
|||
[display, isInWatchParty],
|
||||
);
|
||||
|
||||
// Handle thumbnail toggle with backend save
|
||||
const handleThumbnailToggle = useCallback(() => {
|
||||
const newValue = !enableThumbnails;
|
||||
setEnableThumbnails(newValue);
|
||||
saveThumbnailSetting(newValue);
|
||||
}, [enableThumbnails, setEnableThumbnails, saveThumbnailSetting]);
|
||||
|
||||
// Handle autoplay toggle with backend save
|
||||
const handleAutoplayToggle = useCallback(() => {
|
||||
const newValue = !enableAutoplay;
|
||||
setEnableAutoplay(newValue);
|
||||
saveAutoplaySetting(newValue);
|
||||
}, [enableAutoplay, setEnableAutoplay, saveAutoplaySetting]);
|
||||
|
||||
// Force 1x speed in watch party
|
||||
useEffect(() => {
|
||||
if (isInWatchParty && display && playbackRate !== 1) {
|
||||
|
|
@ -239,23 +289,25 @@ export function PlaybackSettingsView({ id }: { id: string }) {
|
|||
rightSide={
|
||||
<Toggle
|
||||
enabled={enableAutoplay}
|
||||
onClick={() => setEnableAutoplay(!enableAutoplay)}
|
||||
onClick={handleAutoplayToggle}
|
||||
/>
|
||||
}
|
||||
>
|
||||
{t("settings.preferences.autoplayLabel")}
|
||||
</Menu.Link>
|
||||
)}
|
||||
<Menu.Link
|
||||
rightSide={
|
||||
<Toggle
|
||||
enabled={enableThumbnails}
|
||||
onClick={() => setEnableThumbnails(!enableThumbnails)}
|
||||
/>
|
||||
}
|
||||
>
|
||||
{t("settings.preferences.thumbnailLabel")}
|
||||
</Menu.Link>
|
||||
{!enableLowPerformanceMode && (
|
||||
<Menu.Link
|
||||
rightSide={
|
||||
<Toggle
|
||||
enabled={enableThumbnails}
|
||||
onClick={handleThumbnailToggle}
|
||||
/>
|
||||
}
|
||||
>
|
||||
{t("settings.preferences.thumbnailLabel")}
|
||||
</Menu.Link>
|
||||
)}
|
||||
</div>
|
||||
</Menu.Section>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import Hls from "hls.js";
|
||||
import { useCallback, useEffect, useRef } from "react";
|
||||
|
||||
import { playerStatus } from "@/stores/player/slices/source";
|
||||
import { ThumbnailImage } from "@/stores/player/slices/thumbnails";
|
||||
import { usePlayerStore } from "@/stores/player/store";
|
||||
import { LoadableSource, selectQuality } from "@/stores/player/utils/qualities";
|
||||
|
|
@ -125,10 +124,11 @@ class ThumnbnailWorker {
|
|||
|
||||
export function ThumbnailScraper() {
|
||||
const addImage = usePlayerStore((s) => s.thumbnails.addImage);
|
||||
const status = usePlayerStore((s) => s.status);
|
||||
const resetImages = usePlayerStore((s) => s.thumbnails.resetImages);
|
||||
const meta = usePlayerStore((s) => s.meta);
|
||||
const source = usePlayerStore((s) => s.source);
|
||||
const hasPlayedOnce = usePlayerStore((s) => s.mediaPlaying.hasPlayedOnce);
|
||||
const duration = usePlayerStore((s) => s.progress.duration);
|
||||
const enableThumbnails = usePreferencesStore((s) => s.enableThumbnails);
|
||||
const workerRef = useRef<ThumnbnailWorker | null>(null);
|
||||
|
||||
|
|
@ -144,7 +144,8 @@ export function ThumbnailScraper() {
|
|||
});
|
||||
// dont interrupt existing working
|
||||
if (workerRef.current) return;
|
||||
if (status !== playerStatus.PLAYING) return;
|
||||
// Allow thumbnail generation when video is loaded and has duration
|
||||
if (!hasPlayedOnce || duration <= 0) return;
|
||||
if (!inputStream) return;
|
||||
resetImages();
|
||||
const ins = new ThumnbnailWorker({
|
||||
|
|
@ -152,17 +153,17 @@ export function ThumbnailScraper() {
|
|||
});
|
||||
workerRef.current = ins;
|
||||
ins.start(inputStream.stream);
|
||||
}, [source, addImage, resetImages, status]);
|
||||
}, [source, addImage, resetImages, hasPlayedOnce, duration]);
|
||||
|
||||
const startRef = useRef(start);
|
||||
useEffect(() => {
|
||||
startRef.current = start;
|
||||
}, [start, status]);
|
||||
}, [start]);
|
||||
|
||||
// start worker with the stream
|
||||
useEffect(() => {
|
||||
if (enableThumbnails) startRef.current();
|
||||
}, [sourceSeralized, enableThumbnails]);
|
||||
}, [sourceSeralized, enableThumbnails, hasPlayedOnce, duration]);
|
||||
|
||||
// destroy worker on unmount
|
||||
useEffect(() => {
|
||||
|
|
@ -186,7 +187,13 @@ export function ThumbnailScraper() {
|
|||
workerRef.current = null;
|
||||
}
|
||||
if (enableThumbnails) startRef.current();
|
||||
}, [serializedMeta, sourceSeralized, status, enableThumbnails]);
|
||||
}, [
|
||||
serializedMeta,
|
||||
sourceSeralized,
|
||||
enableThumbnails,
|
||||
hasPlayedOnce,
|
||||
duration,
|
||||
]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,14 +70,7 @@ export function PreferencesPart(props: {
|
|||
const navigate = useNavigate();
|
||||
|
||||
const handleLowPerformanceModeToggle = () => {
|
||||
const newMode = !props.enableLowPerformanceMode;
|
||||
props.setEnableLowPerformanceMode(newMode);
|
||||
|
||||
// When enabling low performance mode, disable bandwidth-heavy features
|
||||
if (newMode) {
|
||||
props.setEnableThumbnails(false);
|
||||
props.setEnableAutoplay(false);
|
||||
}
|
||||
props.setEnableLowPerformanceMode(!props.enableLowPerformanceMode);
|
||||
};
|
||||
|
||||
const handleSourceToggle = (sourceId: string) => {
|
||||
|
|
|
|||
|
|
@ -174,6 +174,11 @@ export const usePreferencesStore = create(
|
|||
setEnableLowPerformanceMode(v) {
|
||||
set((s) => {
|
||||
s.enableLowPerformanceMode = v;
|
||||
// When enabling performance mode, disable bandwidth-heavy features
|
||||
if (v) {
|
||||
s.enableThumbnails = false;
|
||||
s.enableAutoplay = false;
|
||||
}
|
||||
});
|
||||
},
|
||||
setEnableNativeSubtitles(v) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue