mirror of
https://github.com/p-stream/p-stream.git
synced 2026-04-21 09:12:16 +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";
|
import classNames from "classnames";
|
||||||
|
|
||||||
export function Toggle(props: { onClick?: () => void; enabled?: boolean }) {
|
export function Toggle(props: {
|
||||||
|
onClick?: () => void;
|
||||||
|
enabled?: boolean;
|
||||||
|
disabled?: boolean;
|
||||||
|
}) {
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={props.onClick}
|
onClick={props.disabled ? undefined : props.onClick}
|
||||||
|
disabled={props.disabled}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"w-11 h-6 p-1 rounded-full grid transition-colors duration-100 group/toggle tabbable",
|
"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.enabled ? "bg-buttons-toggle" : "bg-buttons-toggleDisabled",
|
||||||
|
props.disabled ? "opacity-50 cursor-not-allowed" : null,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="relative w-full h-full">
|
<div className="relative w-full h-full">
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,13 @@ import classNames from "classnames";
|
||||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
|
import { updateSettings } from "@/backend/accounts/settings";
|
||||||
import { Toggle } from "@/components/buttons/Toggle";
|
import { Toggle } from "@/components/buttons/Toggle";
|
||||||
import { Icon, Icons } from "@/components/Icon";
|
import { Icon, Icons } from "@/components/Icon";
|
||||||
import { Menu } from "@/components/player/internals/ContextMenu";
|
import { Menu } from "@/components/player/internals/ContextMenu";
|
||||||
|
import { useBackendUrl } from "@/hooks/auth/useBackendUrl";
|
||||||
import { useOverlayRouter } from "@/hooks/useOverlayRouter";
|
import { useOverlayRouter } from "@/hooks/useOverlayRouter";
|
||||||
|
import { useAuthStore } from "@/stores/auth";
|
||||||
import { usePlayerStore } from "@/stores/player/store";
|
import { usePlayerStore } from "@/stores/player/store";
|
||||||
import { usePreferencesStore } from "@/stores/preferences";
|
import { usePreferencesStore } from "@/stores/preferences";
|
||||||
import { useWatchPartyStore } from "@/stores/watchParty";
|
import { useWatchPartyStore } from "@/stores/watchParty";
|
||||||
|
|
@ -188,10 +191,43 @@ export function PlaybackSettingsView({ id }: { id: string }) {
|
||||||
);
|
);
|
||||||
const isInWatchParty = useWatchPartyStore((s) => s.enabled);
|
const isInWatchParty = useWatchPartyStore((s) => s.enabled);
|
||||||
|
|
||||||
|
const account = useAuthStore((s) => s.account);
|
||||||
|
const backendUrl = useBackendUrl();
|
||||||
const allowAutoplay = useMemo(() => isAutoplayAllowed(), []);
|
const allowAutoplay = useMemo(() => isAutoplayAllowed(), []);
|
||||||
const canShowAutoplay =
|
const canShowAutoplay =
|
||||||
!isInWatchParty && allowAutoplay && !enableLowPerformanceMode;
|
!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(
|
const setPlaybackRate = useCallback(
|
||||||
(v: number) => {
|
(v: number) => {
|
||||||
if (isInWatchParty) return; // Don't allow changes in watch party
|
if (isInWatchParty) return; // Don't allow changes in watch party
|
||||||
|
|
@ -200,6 +236,20 @@ export function PlaybackSettingsView({ id }: { id: string }) {
|
||||||
[display, isInWatchParty],
|
[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
|
// Force 1x speed in watch party
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isInWatchParty && display && playbackRate !== 1) {
|
if (isInWatchParty && display && playbackRate !== 1) {
|
||||||
|
|
@ -239,23 +289,25 @@ export function PlaybackSettingsView({ id }: { id: string }) {
|
||||||
rightSide={
|
rightSide={
|
||||||
<Toggle
|
<Toggle
|
||||||
enabled={enableAutoplay}
|
enabled={enableAutoplay}
|
||||||
onClick={() => setEnableAutoplay(!enableAutoplay)}
|
onClick={handleAutoplayToggle}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{t("settings.preferences.autoplayLabel")}
|
{t("settings.preferences.autoplayLabel")}
|
||||||
</Menu.Link>
|
</Menu.Link>
|
||||||
)}
|
)}
|
||||||
<Menu.Link
|
{!enableLowPerformanceMode && (
|
||||||
rightSide={
|
<Menu.Link
|
||||||
<Toggle
|
rightSide={
|
||||||
enabled={enableThumbnails}
|
<Toggle
|
||||||
onClick={() => setEnableThumbnails(!enableThumbnails)}
|
enabled={enableThumbnails}
|
||||||
/>
|
onClick={handleThumbnailToggle}
|
||||||
}
|
/>
|
||||||
>
|
}
|
||||||
{t("settings.preferences.thumbnailLabel")}
|
>
|
||||||
</Menu.Link>
|
{t("settings.preferences.thumbnailLabel")}
|
||||||
|
</Menu.Link>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Menu.Section>
|
</Menu.Section>
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import Hls from "hls.js";
|
import Hls from "hls.js";
|
||||||
import { useCallback, useEffect, useRef } from "react";
|
import { useCallback, useEffect, useRef } from "react";
|
||||||
|
|
||||||
import { playerStatus } from "@/stores/player/slices/source";
|
|
||||||
import { ThumbnailImage } from "@/stores/player/slices/thumbnails";
|
import { ThumbnailImage } from "@/stores/player/slices/thumbnails";
|
||||||
import { usePlayerStore } from "@/stores/player/store";
|
import { usePlayerStore } from "@/stores/player/store";
|
||||||
import { LoadableSource, selectQuality } from "@/stores/player/utils/qualities";
|
import { LoadableSource, selectQuality } from "@/stores/player/utils/qualities";
|
||||||
|
|
@ -125,10 +124,11 @@ class ThumnbnailWorker {
|
||||||
|
|
||||||
export function ThumbnailScraper() {
|
export function ThumbnailScraper() {
|
||||||
const addImage = usePlayerStore((s) => s.thumbnails.addImage);
|
const addImage = usePlayerStore((s) => s.thumbnails.addImage);
|
||||||
const status = usePlayerStore((s) => s.status);
|
|
||||||
const resetImages = usePlayerStore((s) => s.thumbnails.resetImages);
|
const resetImages = usePlayerStore((s) => s.thumbnails.resetImages);
|
||||||
const meta = usePlayerStore((s) => s.meta);
|
const meta = usePlayerStore((s) => s.meta);
|
||||||
const source = usePlayerStore((s) => s.source);
|
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 enableThumbnails = usePreferencesStore((s) => s.enableThumbnails);
|
||||||
const workerRef = useRef<ThumnbnailWorker | null>(null);
|
const workerRef = useRef<ThumnbnailWorker | null>(null);
|
||||||
|
|
||||||
|
|
@ -144,7 +144,8 @@ export function ThumbnailScraper() {
|
||||||
});
|
});
|
||||||
// dont interrupt existing working
|
// dont interrupt existing working
|
||||||
if (workerRef.current) return;
|
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;
|
if (!inputStream) return;
|
||||||
resetImages();
|
resetImages();
|
||||||
const ins = new ThumnbnailWorker({
|
const ins = new ThumnbnailWorker({
|
||||||
|
|
@ -152,17 +153,17 @@ export function ThumbnailScraper() {
|
||||||
});
|
});
|
||||||
workerRef.current = ins;
|
workerRef.current = ins;
|
||||||
ins.start(inputStream.stream);
|
ins.start(inputStream.stream);
|
||||||
}, [source, addImage, resetImages, status]);
|
}, [source, addImage, resetImages, hasPlayedOnce, duration]);
|
||||||
|
|
||||||
const startRef = useRef(start);
|
const startRef = useRef(start);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
startRef.current = start;
|
startRef.current = start;
|
||||||
}, [start, status]);
|
}, [start]);
|
||||||
|
|
||||||
// start worker with the stream
|
// start worker with the stream
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (enableThumbnails) startRef.current();
|
if (enableThumbnails) startRef.current();
|
||||||
}, [sourceSeralized, enableThumbnails]);
|
}, [sourceSeralized, enableThumbnails, hasPlayedOnce, duration]);
|
||||||
|
|
||||||
// destroy worker on unmount
|
// destroy worker on unmount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -186,7 +187,13 @@ export function ThumbnailScraper() {
|
||||||
workerRef.current = null;
|
workerRef.current = null;
|
||||||
}
|
}
|
||||||
if (enableThumbnails) startRef.current();
|
if (enableThumbnails) startRef.current();
|
||||||
}, [serializedMeta, sourceSeralized, status, enableThumbnails]);
|
}, [
|
||||||
|
serializedMeta,
|
||||||
|
sourceSeralized,
|
||||||
|
enableThumbnails,
|
||||||
|
hasPlayedOnce,
|
||||||
|
duration,
|
||||||
|
]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -70,14 +70,7 @@ export function PreferencesPart(props: {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const handleLowPerformanceModeToggle = () => {
|
const handleLowPerformanceModeToggle = () => {
|
||||||
const newMode = !props.enableLowPerformanceMode;
|
props.setEnableLowPerformanceMode(!props.enableLowPerformanceMode);
|
||||||
props.setEnableLowPerformanceMode(newMode);
|
|
||||||
|
|
||||||
// When enabling low performance mode, disable bandwidth-heavy features
|
|
||||||
if (newMode) {
|
|
||||||
props.setEnableThumbnails(false);
|
|
||||||
props.setEnableAutoplay(false);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSourceToggle = (sourceId: string) => {
|
const handleSourceToggle = (sourceId: string) => {
|
||||||
|
|
|
||||||
|
|
@ -174,6 +174,11 @@ export const usePreferencesStore = create(
|
||||||
setEnableLowPerformanceMode(v) {
|
setEnableLowPerformanceMode(v) {
|
||||||
set((s) => {
|
set((s) => {
|
||||||
s.enableLowPerformanceMode = v;
|
s.enableLowPerformanceMode = v;
|
||||||
|
// When enabling performance mode, disable bandwidth-heavy features
|
||||||
|
if (v) {
|
||||||
|
s.enableThumbnails = false;
|
||||||
|
s.enableAutoplay = false;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
setEnableNativeSubtitles(v) {
|
setEnableNativeSubtitles(v) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue