mirror of
https://github.com/p-stream/p-stream.git
synced 2026-03-28 13:48:51 +00:00
add low performance mode
This commit is contained in:
parent
7b4a013fae
commit
200d3e69ac
16 changed files with 261 additions and 73 deletions
|
|
@ -961,6 +961,7 @@
|
|||
}
|
||||
},
|
||||
"preferences": {
|
||||
"title": "Preferences",
|
||||
"language": "Application language",
|
||||
"languageDescription": "Language applied to the entire application, only English has silly stuff 🙁.",
|
||||
"thumbnail": "Generate thumbnails",
|
||||
|
|
@ -972,9 +973,11 @@
|
|||
"skipCredits": "Skip End Credits",
|
||||
"skipCreditsDescription": "When enabled, automatically play the next episode at 99% completion to skip end credits. When disabled, wait until the episode is fully completed.",
|
||||
"skipCreditsLabel": "Skip end credits",
|
||||
"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",
|
||||
"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>",
|
||||
"title": "Preferences",
|
||||
"sourceOrderEnableLabel": "Custom source order"
|
||||
},
|
||||
"reset": "Reset",
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ export interface SettingsInput {
|
|||
sourceOrder?: string[];
|
||||
enableSourceOrder?: boolean;
|
||||
proxyTmdb?: boolean;
|
||||
enableLowPerformanceMode?: boolean;
|
||||
}
|
||||
|
||||
export interface SettingsResponse {
|
||||
|
|
@ -42,6 +43,7 @@ export interface SettingsResponse {
|
|||
sourceOrder?: string[];
|
||||
enableSourceOrder?: boolean;
|
||||
proxyTmdb?: boolean;
|
||||
enableLowPerformanceMode?: boolean;
|
||||
}
|
||||
|
||||
export function updateSettings(
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import { useAuth } from "@/hooks/auth/useAuth";
|
|||
import { useBackendUrl } from "@/hooks/auth/useBackendUrl";
|
||||
import { conf } from "@/setup/config";
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
import { usePreferencesStore } from "@/stores/preferences";
|
||||
|
||||
function Divider() {
|
||||
return <hr className="border-0 w-full h-px bg-dropdown-border" />;
|
||||
|
|
@ -227,6 +228,10 @@ export function LinksDropdown(props: { children: React.ReactNode }) {
|
|||
setOpen((s) => !s);
|
||||
}, []);
|
||||
|
||||
const enableLowPerformanceMode = usePreferencesStore(
|
||||
(s) => s.enableLowPerformanceMode,
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="relative is-dropdown">
|
||||
<div
|
||||
|
|
@ -271,9 +276,11 @@ export function LinksDropdown(props: { children: React.ReactNode }) {
|
|||
<DropdownLink href="/about" icon={Icons.CIRCLE_QUESTION}>
|
||||
{t("navigation.menu.about")}
|
||||
</DropdownLink>
|
||||
<DropdownLink href="/discover" icon={Icons.RISING_STAR}>
|
||||
{t("navigation.menu.discover")}
|
||||
</DropdownLink>
|
||||
{!enableLowPerformanceMode && (
|
||||
<DropdownLink href="/discover" icon={Icons.RISING_STAR}>
|
||||
{t("navigation.menu.discover")}
|
||||
</DropdownLink>
|
||||
)}
|
||||
<WatchPartyInputLink />
|
||||
{deviceName ? (
|
||||
<DropdownLink
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import { useAuth } from "@/hooks/auth/useAuth";
|
|||
import { BlurEllipsis } from "@/pages/layouts/SubPageLayout";
|
||||
import { conf } from "@/setup/config";
|
||||
import { useBannerSize } from "@/stores/banner";
|
||||
import { usePreferencesStore } from "@/stores/preferences";
|
||||
|
||||
import { BrandPill } from "./BrandPill";
|
||||
|
||||
|
|
@ -52,6 +53,10 @@ export function Navigation(props: NavigationProps) {
|
|||
return minLength + (maxLength - minLength) * (1 - scrollFactor);
|
||||
};
|
||||
|
||||
const enableLowPerformanceMode = usePreferencesStore(
|
||||
(s) => s.enableLowPerformanceMode,
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* lightbar */}
|
||||
|
|
@ -63,7 +68,7 @@ export function Navigation(props: NavigationProps) {
|
|||
}}
|
||||
>
|
||||
<div className="absolute inset-x-0 -mt-[22%] flex items-center sm:mt-0">
|
||||
<Lightbar />
|
||||
<Lightbar noParticles={enableLowPerformanceMode} />
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
|
|
@ -149,33 +154,34 @@ export function Navigation(props: NavigationProps) {
|
|||
navigation
|
||||
/>
|
||||
</a>
|
||||
{window.location.pathname !== "/discover" ? (
|
||||
<a
|
||||
onClick={() => handleClick("/discover")}
|
||||
rel="noreferrer"
|
||||
className="text-xl text-white tabbable rounded-full backdrop-blur-lg"
|
||||
>
|
||||
<IconPatch
|
||||
icon={Icons.RISING_STAR}
|
||||
clickable
|
||||
downsized
|
||||
navigation
|
||||
/>
|
||||
</a>
|
||||
) : (
|
||||
<a
|
||||
onClick={() => handleClick("/")}
|
||||
rel="noreferrer"
|
||||
className="text-lg text-white tabbable rounded-full backdrop-blur-lg"
|
||||
>
|
||||
<IconPatch
|
||||
icon={Icons.SEARCH}
|
||||
clickable
|
||||
downsized
|
||||
navigation
|
||||
/>
|
||||
</a>
|
||||
)}
|
||||
{!enableLowPerformanceMode &&
|
||||
(window.location.pathname !== "/discover" ? (
|
||||
<a
|
||||
onClick={() => handleClick("/discover")}
|
||||
rel="noreferrer"
|
||||
className="text-xl text-white tabbable rounded-full backdrop-blur-lg"
|
||||
>
|
||||
<IconPatch
|
||||
icon={Icons.RISING_STAR}
|
||||
clickable
|
||||
downsized
|
||||
navigation
|
||||
/>
|
||||
</a>
|
||||
) : (
|
||||
<a
|
||||
onClick={() => handleClick("/")}
|
||||
rel="noreferrer"
|
||||
className="text-lg text-white tabbable rounded-full backdrop-blur-lg"
|
||||
>
|
||||
<IconPatch
|
||||
icon={Icons.SEARCH}
|
||||
clickable
|
||||
downsized
|
||||
navigation
|
||||
/>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
<div className="relative pointer-events-auto">
|
||||
<LinksDropdown>
|
||||
|
|
|
|||
|
|
@ -67,6 +67,10 @@ function MediaCardContent({
|
|||
|
||||
const [searchQuery] = useSearchQuery();
|
||||
|
||||
const enableLowPerformanceMode = usePreferencesStore(
|
||||
(state) => state.enableLowPerformanceMode,
|
||||
);
|
||||
|
||||
if (isReleased() && media.year) {
|
||||
dotListContent.push(media.year.toFixed());
|
||||
}
|
||||
|
|
@ -190,7 +194,7 @@ function MediaCardContent({
|
|||
<DotList className="text-xs" content={dotListContent} />
|
||||
</div>
|
||||
|
||||
{!closable && (
|
||||
{!closable && !enableLowPerformanceMode && (
|
||||
<div className="absolute bottom-0 translate-y-1 right-1">
|
||||
<button
|
||||
className="media-more-button p-2"
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { Icons } from "@/components/Icon";
|
|||
import { DetailsModal } from "@/components/overlays/details/DetailsModal";
|
||||
import { useModal } from "@/components/overlays/Modal";
|
||||
import { usePlayerStore } from "@/stores/player/store";
|
||||
import { usePreferencesStore } from "@/stores/preferences";
|
||||
|
||||
import { VideoPlayerButton } from "./Button";
|
||||
|
||||
|
|
@ -30,6 +31,14 @@ export function InfoButton() {
|
|||
modal.show();
|
||||
};
|
||||
|
||||
const enableLowPerformanceMode = usePreferencesStore(
|
||||
(state) => state.enableLowPerformanceMode,
|
||||
);
|
||||
|
||||
if (enableLowPerformanceMode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<VideoPlayerButton
|
||||
|
|
|
|||
|
|
@ -413,13 +413,13 @@ function ParticlesCanvas() {
|
|||
return <canvas className="particles" ref={canvasRef} />;
|
||||
}
|
||||
|
||||
export function Lightbar(props: { className?: string }) {
|
||||
export function Lightbar(props: { className?: string; noParticles?: boolean }) {
|
||||
return (
|
||||
<div className="absolute inset-0 w-full h-[680px] overflow-hidden pointer-events-none -mt-64">
|
||||
<div className="max-w-screen w-full h-[680px] relative pt-64">
|
||||
<div className={props.className}>
|
||||
<div className="lightbar">
|
||||
<ParticlesCanvas />
|
||||
{!props.noParticles && <ParticlesCanvas />}
|
||||
<div className="lightbar-visual" />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -54,6 +54,10 @@ export function useAuthData() {
|
|||
);
|
||||
const setProxyTmdb = usePreferencesStore((s) => s.setProxyTmdb);
|
||||
|
||||
const setEnableLowPerformanceMode = usePreferencesStore(
|
||||
(s) => s.setEnableLowPerformanceMode,
|
||||
);
|
||||
|
||||
const login = useCallback(
|
||||
async (
|
||||
loginResponse: LoginResponse,
|
||||
|
|
@ -156,6 +160,10 @@ export function useAuthData() {
|
|||
if (settings.febboxKey !== undefined) {
|
||||
setFebboxKey(settings.febboxKey);
|
||||
}
|
||||
|
||||
if (settings.enableLowPerformanceMode !== undefined) {
|
||||
setEnableLowPerformanceMode(settings.enableLowPerformanceMode);
|
||||
}
|
||||
},
|
||||
[
|
||||
replaceBookmarks,
|
||||
|
|
@ -176,6 +184,7 @@ export function useAuthData() {
|
|||
setEnableSourceOrder,
|
||||
setProxyTmdb,
|
||||
setFebboxKey,
|
||||
setEnableLowPerformanceMode,
|
||||
],
|
||||
);
|
||||
|
||||
|
|
|
|||
16
src/hooks/useLowPerformanceMode.ts
Normal file
16
src/hooks/useLowPerformanceMode.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import { useEffect } from "react";
|
||||
|
||||
import { usePreferencesStore } from "@/stores/preferences";
|
||||
|
||||
export function useLowPerformanceMode() {
|
||||
const setEnableLowPerformanceMode = usePreferencesStore(
|
||||
(s) => s.setEnableLowPerformanceMode,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
if (urlParams.has("low-performance")) {
|
||||
setEnableLowPerformanceMode(true);
|
||||
}
|
||||
}, [setEnableLowPerformanceMode]);
|
||||
}
|
||||
|
|
@ -64,6 +64,7 @@ export function useSettingsState(
|
|||
enableImageLogos: boolean,
|
||||
enableCarouselView: boolean,
|
||||
forceCompactEpisodeView: boolean,
|
||||
enableLowPerformanceMode: boolean,
|
||||
) {
|
||||
const [proxyUrlsState, setProxyUrls, resetProxyUrls, proxyUrlsChanged] =
|
||||
useDerived(proxyUrls);
|
||||
|
|
@ -167,6 +168,12 @@ export function useSettingsState(
|
|||
resetForceCompactEpisodeView,
|
||||
forceCompactEpisodeViewChanged,
|
||||
] = useDerived(forceCompactEpisodeView);
|
||||
const [
|
||||
enableLowPerformanceModeState,
|
||||
setEnableLowPerformanceModeState,
|
||||
resetEnableLowPerformanceMode,
|
||||
enableLowPerformanceModeChanged,
|
||||
] = useDerived(enableLowPerformanceMode);
|
||||
|
||||
function reset() {
|
||||
resetTheme();
|
||||
|
|
@ -191,6 +198,7 @@ export function useSettingsState(
|
|||
resetProxyTmdb();
|
||||
resetEnableCarouselView();
|
||||
resetForceCompactEpisodeView();
|
||||
resetEnableLowPerformanceMode();
|
||||
}
|
||||
|
||||
const changed =
|
||||
|
|
@ -214,7 +222,8 @@ export function useSettingsState(
|
|||
enableSourceOrderChanged ||
|
||||
proxyTmdbChanged ||
|
||||
enableCarouselViewChanged ||
|
||||
forceCompactEpisodeViewChanged;
|
||||
forceCompactEpisodeViewChanged ||
|
||||
enableLowPerformanceModeChanged;
|
||||
|
||||
return {
|
||||
reset,
|
||||
|
|
@ -324,5 +333,10 @@ export function useSettingsState(
|
|||
set: setForceCompactEpisodeViewState,
|
||||
changed: forceCompactEpisodeViewChanged,
|
||||
},
|
||||
enableLowPerformanceMode: {
|
||||
state: enableLowPerformanceModeState,
|
||||
set: setEnableLowPerformanceModeState,
|
||||
changed: enableLowPerformanceModeChanged,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,6 +70,9 @@ export function HomePage() {
|
|||
const enableCarouselView = usePreferencesStore(
|
||||
(state) => state.enableCarouselView,
|
||||
);
|
||||
const enableLowPerformanceMode = usePreferencesStore(
|
||||
(state) => state.enableLowPerformanceMode,
|
||||
);
|
||||
|
||||
const handleClick = (path: To) => {
|
||||
window.scrollTo(0, 0);
|
||||
|
|
@ -168,7 +171,8 @@ export function HomePage() {
|
|||
{/* Under user content */}
|
||||
<WideContainer ultraWide classNames="!px-3 md:!px-9">
|
||||
{/* Empty text */}
|
||||
{!(showBookmarks || showWatching) && !enableDiscover ? (
|
||||
{!(showBookmarks || showWatching) &&
|
||||
(!enableDiscover || enableLowPerformanceMode) ? (
|
||||
<div className="flex flex-col translate-y-[-30px] items-center justify-center pt-20">
|
||||
<p className="text-[18.5px] pb-3">{emptyText}</p>
|
||||
</div>
|
||||
|
|
@ -186,12 +190,12 @@ export function HomePage() {
|
|||
{/* there... perfect. */}
|
||||
|
||||
{/* Discover section or discover button */}
|
||||
{enableDiscover && !search ? (
|
||||
{enableDiscover && !search && !enableLowPerformanceMode ? (
|
||||
<DiscoverContent />
|
||||
) : (
|
||||
<div className="flex flex-col justify-center items-center h-40 space-y-4">
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
{!search && (
|
||||
{!search && !enableLowPerformanceMode && (
|
||||
<Button
|
||||
className="px-py p-[0.35em] mt-3 rounded-xl text-type-dimmed box-content text-[18px] bg-largeCard-background justify-center items-center"
|
||||
onClick={() => handleClick("/discover")}
|
||||
|
|
|
|||
|
|
@ -185,6 +185,13 @@ export function SettingsPage() {
|
|||
(s) => s.setForceCompactEpisodeView,
|
||||
);
|
||||
|
||||
const enableLowPerformanceMode = usePreferencesStore(
|
||||
(s) => s.enableLowPerformanceMode,
|
||||
);
|
||||
const setEnableLowPerformanceMode = usePreferencesStore(
|
||||
(s) => s.setEnableLowPerformanceMode,
|
||||
);
|
||||
|
||||
const account = useAuthStore((s) => s.account);
|
||||
const updateProfile = useAuthStore((s) => s.setAccountProfile);
|
||||
const updateDeviceName = useAuthStore((s) => s.updateDeviceName);
|
||||
|
|
@ -235,6 +242,7 @@ export function SettingsPage() {
|
|||
enableImageLogos,
|
||||
enableCarouselView,
|
||||
forceCompactEpisodeView,
|
||||
enableLowPerformanceMode,
|
||||
);
|
||||
|
||||
const availableSources = useMemo(() => {
|
||||
|
|
@ -291,7 +299,8 @@ export function SettingsPage() {
|
|||
state.enableSourceOrder.changed ||
|
||||
state.proxyTmdb.changed ||
|
||||
state.enableCarouselView.changed ||
|
||||
state.forceCompactEpisodeView.changed
|
||||
state.forceCompactEpisodeView.changed ||
|
||||
state.enableLowPerformanceMode.changed
|
||||
) {
|
||||
await updateSettings(backendUrl, account, {
|
||||
applicationLanguage: state.appLanguage.state,
|
||||
|
|
@ -311,6 +320,7 @@ export function SettingsPage() {
|
|||
proxyTmdb: state.proxyTmdb.state,
|
||||
enableCarouselView: state.enableCarouselView.state,
|
||||
forceCompactEpisodeView: state.forceCompactEpisodeView.state,
|
||||
enableLowPerformanceMode: state.enableLowPerformanceMode.state,
|
||||
});
|
||||
}
|
||||
if (state.deviceName.changed) {
|
||||
|
|
@ -348,6 +358,7 @@ export function SettingsPage() {
|
|||
setProxyTmdb(state.proxyTmdb.state);
|
||||
setEnableCarouselView(state.enableCarouselView.state);
|
||||
setForceCompactEpisodeView(state.forceCompactEpisodeView.state);
|
||||
setEnableLowPerformanceMode(state.enableLowPerformanceMode.state);
|
||||
|
||||
if (state.profile.state) {
|
||||
updateProfile(state.profile.state);
|
||||
|
|
@ -390,6 +401,7 @@ export function SettingsPage() {
|
|||
setProxyTmdb,
|
||||
setEnableCarouselView,
|
||||
setForceCompactEpisodeView,
|
||||
setEnableLowPerformanceMode,
|
||||
]);
|
||||
return (
|
||||
<SubPageLayout>
|
||||
|
|
@ -438,6 +450,8 @@ export function SettingsPage() {
|
|||
setSourceOrder={state.sourceOrder.set}
|
||||
enableSourceOrder={state.enableSourceOrder.state}
|
||||
setenableSourceOrder={state.enableSourceOrder.set}
|
||||
enableLowPerformanceMode={state.enableLowPerformanceMode.state}
|
||||
setEnableLowPerformanceMode={state.enableLowPerformanceMode.set}
|
||||
/>
|
||||
</div>
|
||||
<div id="settings-appearance" className="mt-28">
|
||||
|
|
@ -457,6 +471,7 @@ export function SettingsPage() {
|
|||
setEnableCarouselView={state.enableCarouselView.set}
|
||||
forceCompactEpisodeView={state.forceCompactEpisodeView.state}
|
||||
setForceCompactEpisodeView={state.forceCompactEpisodeView.set}
|
||||
enableLowPerformanceMode={state.enableLowPerformanceMode.state}
|
||||
/>
|
||||
</div>
|
||||
<div id="settings-captions" className="mt-28">
|
||||
|
|
|
|||
|
|
@ -219,6 +219,8 @@ export function AppearancePart(props: {
|
|||
|
||||
forceCompactEpisodeView: boolean;
|
||||
setForceCompactEpisodeView: (v: boolean) => void;
|
||||
|
||||
enableLowPerformanceMode: boolean;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
|
|
@ -227,6 +229,33 @@ export function AppearancePart(props: {
|
|||
const [isAtTop, setIsAtTop] = useState(true);
|
||||
const [isAtBottom, setIsAtBottom] = useState(false);
|
||||
|
||||
const {
|
||||
enableLowPerformanceMode,
|
||||
setEnableDiscover,
|
||||
setEnableFeatured,
|
||||
setEnableDetailsModal,
|
||||
setEnableImageLogos,
|
||||
setForceCompactEpisodeView,
|
||||
} = props;
|
||||
|
||||
// Apply low performance mode restrictions
|
||||
useEffect(() => {
|
||||
if (enableLowPerformanceMode) {
|
||||
setEnableDiscover(false);
|
||||
setEnableFeatured(false);
|
||||
setEnableDetailsModal(false);
|
||||
setEnableImageLogos(false);
|
||||
setForceCompactEpisodeView(true);
|
||||
}
|
||||
}, [
|
||||
enableLowPerformanceMode,
|
||||
setEnableDiscover,
|
||||
setEnableFeatured,
|
||||
setEnableDetailsModal,
|
||||
setEnableImageLogos,
|
||||
setForceCompactEpisodeView,
|
||||
]);
|
||||
|
||||
const checkScrollPosition = () => {
|
||||
const container = carouselRef.current;
|
||||
if (!container) return;
|
||||
|
|
@ -285,13 +314,20 @@ export function AppearancePart(props: {
|
|||
</p>
|
||||
<div
|
||||
onClick={() => {
|
||||
const newDiscoverValue = !props.enableDiscover;
|
||||
props.setEnableDiscover(newDiscoverValue);
|
||||
if (!newDiscoverValue) {
|
||||
props.setEnableFeatured(false);
|
||||
if (!props.enableLowPerformanceMode) {
|
||||
const newDiscoverValue = !props.enableDiscover;
|
||||
props.setEnableDiscover(newDiscoverValue);
|
||||
if (!newDiscoverValue) {
|
||||
props.setEnableFeatured(false);
|
||||
}
|
||||
}
|
||||
}}
|
||||
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"
|
||||
className={classNames(
|
||||
"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",
|
||||
props.enableLowPerformanceMode
|
||||
? "cursor-not-allowed opacity-50 pointer-events-none"
|
||||
: "cursor-pointer opacity-100 pointer-events-auto",
|
||||
)}
|
||||
>
|
||||
<Toggle enabled={props.enableDiscover} />
|
||||
<p className="flex-1 text-white font-bold">
|
||||
|
|
@ -300,7 +336,7 @@ export function AppearancePart(props: {
|
|||
</div>
|
||||
</div>
|
||||
{/* Featured Carousel */}
|
||||
{props.enableDiscover && (
|
||||
{props.enableDiscover && !props.enableLowPerformanceMode && (
|
||||
<div className="pt-4 pl-4 border-l-8 border-dropdown-background">
|
||||
<p className="text-white font-bold mb-3">
|
||||
{t("settings.appearance.options.featured")}
|
||||
|
|
@ -329,11 +365,14 @@ export function AppearancePart(props: {
|
|||
</p>
|
||||
<div
|
||||
onClick={() =>
|
||||
!props.enableLowPerformanceMode &&
|
||||
props.setEnableDetailsModal(!props.enableDetailsModal)
|
||||
}
|
||||
className={classNames(
|
||||
"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",
|
||||
"cursor-pointer opacity-100 pointer-events-auto",
|
||||
props.enableLowPerformanceMode
|
||||
? "cursor-not-allowed opacity-50 pointer-events-none"
|
||||
: "cursor-pointer opacity-100 pointer-events-auto",
|
||||
)}
|
||||
>
|
||||
<Toggle enabled={props.enableDetailsModal} />
|
||||
|
|
@ -356,10 +395,15 @@ export function AppearancePart(props: {
|
|||
{t("settings.appearance.options.logosNotice")}
|
||||
</p>
|
||||
<div
|
||||
onClick={() => props.setEnableImageLogos(!props.enableImageLogos)}
|
||||
onClick={() =>
|
||||
!props.enableLowPerformanceMode &&
|
||||
props.setEnableImageLogos(!props.enableImageLogos)
|
||||
}
|
||||
className={classNames(
|
||||
"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",
|
||||
"cursor-pointer opacity-100 pointer-events-auto",
|
||||
props.enableLowPerformanceMode
|
||||
? "cursor-not-allowed opacity-50 pointer-events-none"
|
||||
: "cursor-pointer opacity-100 pointer-events-auto",
|
||||
)}
|
||||
>
|
||||
<Toggle enabled={props.enableImageLogos} />
|
||||
|
|
@ -405,11 +449,14 @@ export function AppearancePart(props: {
|
|||
</p>
|
||||
<div
|
||||
onClick={() =>
|
||||
!props.enableLowPerformanceMode &&
|
||||
props.setForceCompactEpisodeView(!props.forceCompactEpisodeView)
|
||||
}
|
||||
className={classNames(
|
||||
"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",
|
||||
"cursor-pointer opacity-100 pointer-events-auto",
|
||||
props.enableLowPerformanceMode
|
||||
? "cursor-not-allowed opacity-50 pointer-events-none"
|
||||
: "cursor-pointer opacity-100 pointer-events-auto",
|
||||
)}
|
||||
>
|
||||
<Toggle enabled={props.forceCompactEpisodeView} />
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ export function PreferencesPart(props: {
|
|||
setSourceOrder: (v: string[]) => void;
|
||||
enableSourceOrder: boolean;
|
||||
setenableSourceOrder: (v: boolean) => void;
|
||||
enableLowPerformanceMode: boolean;
|
||||
setEnableLowPerformanceMode: (v: boolean) => void;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const sorted = sortLangCodes(appLanguageOptions.map((item) => item.code));
|
||||
|
|
@ -58,6 +60,17 @@ 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);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-12">
|
||||
<Heading1 border>{t("settings.preferences.title")}</Heading1>
|
||||
|
|
@ -89,8 +102,17 @@ export function PreferencesPart(props: {
|
|||
{t("settings.preferences.thumbnailDescription")}
|
||||
</p>
|
||||
<div
|
||||
onClick={() => props.setEnableThumbnails(!props.enableThumbnails)}
|
||||
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"
|
||||
onClick={() => {
|
||||
if (!props.enableLowPerformanceMode) {
|
||||
props.setEnableThumbnails(!props.enableThumbnails);
|
||||
}
|
||||
}}
|
||||
className={classNames(
|
||||
"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",
|
||||
props.enableLowPerformanceMode
|
||||
? "cursor-not-allowed opacity-50 pointer-events-none"
|
||||
: "cursor-pointer opacity-100 pointer-events-auto",
|
||||
)}
|
||||
>
|
||||
<Toggle enabled={props.enableThumbnails} />
|
||||
<p className="flex-1 text-white font-bold">
|
||||
|
|
@ -109,13 +131,13 @@ export function PreferencesPart(props: {
|
|||
</p>
|
||||
<div
|
||||
onClick={() =>
|
||||
allowAutoplay
|
||||
allowAutoplay && !props.enableLowPerformanceMode
|
||||
? props.setEnableAutoplay(!props.enableAutoplay)
|
||||
: null
|
||||
}
|
||||
className={classNames(
|
||||
"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",
|
||||
allowAutoplay
|
||||
allowAutoplay && !props.enableLowPerformanceMode
|
||||
? "cursor-pointer opacity-100 pointer-events-auto"
|
||||
: "cursor-not-allowed opacity-50 pointer-events-none",
|
||||
)}
|
||||
|
|
@ -127,27 +149,47 @@ export function PreferencesPart(props: {
|
|||
</div>
|
||||
|
||||
{/* Skip End Credits Preference */}
|
||||
{props.enableAutoplay && allowAutoplay && (
|
||||
<div className="pt-4 pl-4 border-l-8 border-dropdown-background">
|
||||
<p className="text-white font-bold mb-3">
|
||||
{t("settings.preferences.skipCredits")}
|
||||
</p>
|
||||
<p className="max-w-[25rem] font-medium">
|
||||
{t("settings.preferences.skipCreditsDescription")}
|
||||
</p>
|
||||
<div
|
||||
onClick={() =>
|
||||
props.setEnableSkipCredits(!props.enableSkipCredits)
|
||||
}
|
||||
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.enableSkipCredits} />
|
||||
<p className="flex-1 text-white font-bold">
|
||||
{t("settings.preferences.skipCreditsLabel")}
|
||||
{props.enableAutoplay &&
|
||||
allowAutoplay &&
|
||||
!props.enableLowPerformanceMode && (
|
||||
<div className="pt-4 pl-4 border-l-8 border-dropdown-background">
|
||||
<p className="text-white font-bold mb-3">
|
||||
{t("settings.preferences.skipCredits")}
|
||||
</p>
|
||||
<p className="max-w-[25rem] font-medium">
|
||||
{t("settings.preferences.skipCreditsDescription")}
|
||||
</p>
|
||||
<div
|
||||
onClick={() =>
|
||||
props.setEnableSkipCredits(!props.enableSkipCredits)
|
||||
}
|
||||
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.enableSkipCredits} />
|
||||
<p className="flex-1 text-white font-bold">
|
||||
{t("settings.preferences.skipCreditsLabel")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
)}
|
||||
</div>
|
||||
{/* Low Performance Mode */}
|
||||
<div>
|
||||
<p className="text-white font-bold mb-3">
|
||||
{t("settings.preferences.lowPerformanceMode")}
|
||||
</p>
|
||||
<p className="max-w-[25rem] font-medium">
|
||||
{t("settings.preferences.lowPerformanceModeDescription")}
|
||||
</p>
|
||||
<div
|
||||
onClick={handleLowPerformanceModeToggle}
|
||||
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.enableLowPerformanceMode} />
|
||||
<p className="flex-1 text-white font-bold">
|
||||
{t("settings.preferences.lowPerformanceModeLabel")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import {
|
|||
|
||||
import { convertLegacyUrl, isLegacyUrl } from "@/backend/metadata/getmeta";
|
||||
import { generateQuickSearchMediaUrl } from "@/backend/metadata/tmdb";
|
||||
import { useLowPerformanceMode } from "@/hooks/useLowPerformanceMode";
|
||||
import { useOnlineListener } from "@/hooks/usePing";
|
||||
import { AboutPage } from "@/pages/About";
|
||||
import { AdminPage } from "@/pages/admin/AdminPage";
|
||||
|
|
@ -98,6 +99,7 @@ export const maintenanceTime = "March 31th 11:00 PM - 5:00 AM EST";
|
|||
function App() {
|
||||
useHistoryListener();
|
||||
useOnlineListener();
|
||||
useLowPerformanceMode(); // Check for ?lp parameter in URL
|
||||
const maintenance = false; // Shows maintance page
|
||||
const [showDowntime, setShowDowntime] = useState(maintenance);
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ export interface PreferencesStore {
|
|||
proxyTmdb: boolean;
|
||||
febboxKey: string | null;
|
||||
realDebridKey: string | null;
|
||||
enableLowPerformanceMode: boolean;
|
||||
|
||||
setEnableThumbnails(v: boolean): void;
|
||||
setEnableAutoplay(v: boolean): void;
|
||||
|
|
@ -32,6 +33,7 @@ export interface PreferencesStore {
|
|||
setProxyTmdb(v: boolean): void;
|
||||
setFebboxKey(v: string | null): void;
|
||||
setRealDebridKey(v: string | null): void;
|
||||
setEnableLowPerformanceMode(v: boolean): void;
|
||||
}
|
||||
|
||||
export const usePreferencesStore = create(
|
||||
|
|
@ -51,6 +53,7 @@ export const usePreferencesStore = create(
|
|||
proxyTmdb: false,
|
||||
febboxKey: null,
|
||||
realDebridKey: null,
|
||||
enableLowPerformanceMode: false,
|
||||
setEnableThumbnails(v) {
|
||||
set((s) => {
|
||||
s.enableThumbnails = v;
|
||||
|
|
@ -121,6 +124,11 @@ export const usePreferencesStore = create(
|
|||
s.realDebridKey = v;
|
||||
});
|
||||
},
|
||||
setEnableLowPerformanceMode(v) {
|
||||
set((s) => {
|
||||
s.enableLowPerformanceMode = v;
|
||||
});
|
||||
},
|
||||
})),
|
||||
{
|
||||
name: "__MW::preferences",
|
||||
|
|
|
|||
Loading…
Reference in a new issue