mirror of
https://github.com/p-stream/p-stream.git
synced 2026-04-21 06:02:39 +00:00
Add toggle for skipping at 99%
This commit is contained in:
parent
81138d5d90
commit
1aa47cfe7c
6 changed files with 76 additions and 4 deletions
|
|
@ -673,6 +673,9 @@
|
||||||
"autoplay": "Autoplay",
|
"autoplay": "Autoplay",
|
||||||
"autoplayDescription": "Automatically play the next episode in a series after reaching the end. Can be enabled by users with the browser extension, a custom proxy, or with the default setup if allowed by the host.",
|
"autoplayDescription": "Automatically play the next episode in a series after reaching the end. Can be enabled by users with the browser extension, a custom proxy, or with the default setup if allowed by the host.",
|
||||||
"autoplayLabel": "Autoplay",
|
"autoplayLabel": "Autoplay",
|
||||||
|
"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",
|
||||||
"sourceOrder": "Reordering sources",
|
"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>",
|
"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",
|
"title": "Preferences",
|
||||||
|
|
|
||||||
|
|
@ -101,13 +101,14 @@ export function NextEpisodeButton(props: {
|
||||||
const { setDirectMeta } = usePlayerMeta();
|
const { setDirectMeta } = usePlayerMeta();
|
||||||
const metaType = usePlayerStore((s) => s.meta?.type);
|
const metaType = usePlayerStore((s) => s.meta?.type);
|
||||||
const time = usePlayerStore((s) => s.progress.time);
|
const time = usePlayerStore((s) => s.progress.time);
|
||||||
|
const enableAutoplay = usePreferencesStore((s) => s.enableAutoplay);
|
||||||
|
const enableSkipCredits = usePreferencesStore((s) => s.enableSkipCredits);
|
||||||
const showingState = shouldShowNextEpisodeButton(time, duration);
|
const showingState = shouldShowNextEpisodeButton(time, duration);
|
||||||
const status = usePlayerStore((s) => s.status);
|
const status = usePlayerStore((s) => s.status);
|
||||||
const setShouldStartFromBeginning = usePlayerStore(
|
const setShouldStartFromBeginning = usePlayerStore(
|
||||||
(s) => s.setShouldStartFromBeginning,
|
(s) => s.setShouldStartFromBeginning,
|
||||||
);
|
);
|
||||||
const updateItem = useProgressStore((s) => s.updateItem);
|
const updateItem = useProgressStore((s) => s.updateItem);
|
||||||
const enableAutoplay = usePreferencesStore((s) => s.enableAutoplay);
|
|
||||||
|
|
||||||
const isLastEpisode =
|
const isLastEpisode =
|
||||||
!meta?.episode?.number || !meta?.episodes?.at(-1)?.number
|
!meta?.episode?.number || !meta?.episodes?.at(-1)?.number
|
||||||
|
|
@ -187,14 +188,25 @@ export function NextEpisodeButton(props: {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!enableAutoplay || metaType !== "show") return;
|
if (!enableAutoplay || metaType !== "show") return;
|
||||||
const onePercent = duration / 100;
|
const onePercent = duration / 100;
|
||||||
const isEnding = time >= duration - onePercent && duration !== 0;
|
|
||||||
|
// When skipCredits is enabled, use the 99% threshold; otherwise require 100% completion
|
||||||
|
const isEnding = enableSkipCredits
|
||||||
|
? time >= duration - onePercent && duration !== 0 // 99% completion
|
||||||
|
: time >= duration && duration !== 0; // 100% completion
|
||||||
|
|
||||||
if (duration === 0) hasAutoplayed.current = false;
|
if (duration === 0) hasAutoplayed.current = false;
|
||||||
if (isEnding && isAutoplayAllowed() && !hasAutoplayed.current) {
|
if (isEnding && isAutoplayAllowed() && !hasAutoplayed.current) {
|
||||||
hasAutoplayed.current = true;
|
hasAutoplayed.current = true;
|
||||||
loadNextEpisode();
|
loadNextEpisode();
|
||||||
}
|
}
|
||||||
}, [duration, enableAutoplay, loadNextEpisode, metaType, time]);
|
}, [
|
||||||
|
duration,
|
||||||
|
enableAutoplay,
|
||||||
|
enableSkipCredits,
|
||||||
|
loadNextEpisode,
|
||||||
|
metaType,
|
||||||
|
time,
|
||||||
|
]);
|
||||||
|
|
||||||
if (!meta?.episode || !nextEp) return null;
|
if (!meta?.episode || !nextEp) return null;
|
||||||
if (metaType !== "show") return null;
|
if (metaType !== "show") return null;
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,7 @@ export function useSettingsState(
|
||||||
sourceOrder: string[],
|
sourceOrder: string[],
|
||||||
enableSourceOrder: boolean,
|
enableSourceOrder: boolean,
|
||||||
proxyTmdb: boolean,
|
proxyTmdb: boolean,
|
||||||
|
enableSkipCredits: boolean,
|
||||||
) {
|
) {
|
||||||
const [proxyUrlsState, setProxyUrls, resetProxyUrls, proxyUrlsChanged] =
|
const [proxyUrlsState, setProxyUrls, resetProxyUrls, proxyUrlsChanged] =
|
||||||
useDerived(proxyUrls);
|
useDerived(proxyUrls);
|
||||||
|
|
@ -103,6 +104,12 @@ export function useSettingsState(
|
||||||
resetEnableAutoplay,
|
resetEnableAutoplay,
|
||||||
enableAutoplayChanged,
|
enableAutoplayChanged,
|
||||||
] = useDerived(enableAutoplay);
|
] = useDerived(enableAutoplay);
|
||||||
|
const [
|
||||||
|
enableSkipCreditsState,
|
||||||
|
setEnableSkipCreditsState,
|
||||||
|
resetEnableSkipCredits,
|
||||||
|
enableSkipCreditsChanged,
|
||||||
|
] = useDerived(enableSkipCredits);
|
||||||
const [
|
const [
|
||||||
enableDiscoverState,
|
enableDiscoverState,
|
||||||
setEnableDiscoverState,
|
setEnableDiscoverState,
|
||||||
|
|
@ -142,6 +149,7 @@ export function useSettingsState(
|
||||||
resetProfile();
|
resetProfile();
|
||||||
resetEnableThumbnails();
|
resetEnableThumbnails();
|
||||||
resetEnableAutoplay();
|
resetEnableAutoplay();
|
||||||
|
resetEnableSkipCredits();
|
||||||
resetEnableDiscover();
|
resetEnableDiscover();
|
||||||
resetEnablePopDetails();
|
resetEnablePopDetails();
|
||||||
resetSourceOrder();
|
resetSourceOrder();
|
||||||
|
|
@ -160,6 +168,7 @@ export function useSettingsState(
|
||||||
profileChanged ||
|
profileChanged ||
|
||||||
enableThumbnailsChanged ||
|
enableThumbnailsChanged ||
|
||||||
enableAutoplayChanged ||
|
enableAutoplayChanged ||
|
||||||
|
enableSkipCreditsChanged ||
|
||||||
enableDiscoverChanged ||
|
enableDiscoverChanged ||
|
||||||
enablePopDetailsChanged ||
|
enablePopDetailsChanged ||
|
||||||
sourceOrderChanged ||
|
sourceOrderChanged ||
|
||||||
|
|
@ -219,6 +228,11 @@ export function useSettingsState(
|
||||||
set: setEnableAutoplayState,
|
set: setEnableAutoplayState,
|
||||||
changed: enableAutoplayChanged,
|
changed: enableAutoplayChanged,
|
||||||
},
|
},
|
||||||
|
enableSkipCredits: {
|
||||||
|
state: enableSkipCreditsState,
|
||||||
|
set: setEnableSkipCreditsState,
|
||||||
|
changed: enableSkipCreditsChanged,
|
||||||
|
},
|
||||||
enableDiscover: {
|
enableDiscover: {
|
||||||
state: enableDiscoverState,
|
state: enableDiscoverState,
|
||||||
set: setEnableDiscoverState,
|
set: setEnableDiscoverState,
|
||||||
|
|
|
||||||
|
|
@ -140,6 +140,11 @@ export function SettingsPage() {
|
||||||
const enableAutoplay = usePreferencesStore((s) => s.enableAutoplay);
|
const enableAutoplay = usePreferencesStore((s) => s.enableAutoplay);
|
||||||
const setEnableAutoplay = usePreferencesStore((s) => s.setEnableAutoplay);
|
const setEnableAutoplay = usePreferencesStore((s) => s.setEnableAutoplay);
|
||||||
|
|
||||||
|
const enableSkipCredits = usePreferencesStore((s) => s.enableSkipCredits);
|
||||||
|
const setEnableSkipCredits = usePreferencesStore(
|
||||||
|
(s) => s.setEnableSkipCredits,
|
||||||
|
);
|
||||||
|
|
||||||
const sourceOrder = usePreferencesStore((s) => s.sourceOrder);
|
const sourceOrder = usePreferencesStore((s) => s.sourceOrder);
|
||||||
const setSourceOrder = usePreferencesStore((s) => s.setSourceOrder);
|
const setSourceOrder = usePreferencesStore((s) => s.setSourceOrder);
|
||||||
|
|
||||||
|
|
@ -178,7 +183,7 @@ export function SettingsPage() {
|
||||||
proxySet,
|
proxySet,
|
||||||
backendUrlSetting,
|
backendUrlSetting,
|
||||||
febboxToken,
|
febboxToken,
|
||||||
account?.profile,
|
account ? account.profile : undefined,
|
||||||
enableThumbnails,
|
enableThumbnails,
|
||||||
enableAutoplay,
|
enableAutoplay,
|
||||||
enableDiscover,
|
enableDiscover,
|
||||||
|
|
@ -186,6 +191,7 @@ export function SettingsPage() {
|
||||||
sourceOrder,
|
sourceOrder,
|
||||||
enableSourceOrder,
|
enableSourceOrder,
|
||||||
proxyTmdb,
|
proxyTmdb,
|
||||||
|
enableSkipCredits,
|
||||||
);
|
);
|
||||||
|
|
||||||
const availableSources = useMemo(() => {
|
const availableSources = useMemo(() => {
|
||||||
|
|
@ -256,6 +262,7 @@ export function SettingsPage() {
|
||||||
|
|
||||||
setEnableThumbnails(state.enableThumbnails.state);
|
setEnableThumbnails(state.enableThumbnails.state);
|
||||||
setEnableAutoplay(state.enableAutoplay.state);
|
setEnableAutoplay(state.enableAutoplay.state);
|
||||||
|
setEnableSkipCredits(state.enableSkipCredits.state);
|
||||||
setEnableDiscover(state.enableDiscover.state);
|
setEnableDiscover(state.enableDiscover.state);
|
||||||
setEnablePopDetails(state.enablePopDetails.state);
|
setEnablePopDetails(state.enablePopDetails.state);
|
||||||
setSourceOrder(state.sourceOrder.state);
|
setSourceOrder(state.sourceOrder.state);
|
||||||
|
|
@ -289,6 +296,7 @@ export function SettingsPage() {
|
||||||
setFebboxToken,
|
setFebboxToken,
|
||||||
state,
|
state,
|
||||||
setEnableAutoplay,
|
setEnableAutoplay,
|
||||||
|
setEnableSkipCredits,
|
||||||
setEnableDiscover,
|
setEnableDiscover,
|
||||||
setEnablePopDetails,
|
setEnablePopDetails,
|
||||||
setSourceOrder,
|
setSourceOrder,
|
||||||
|
|
@ -344,6 +352,8 @@ export function SettingsPage() {
|
||||||
setEnableThumbnails={state.enableThumbnails.set}
|
setEnableThumbnails={state.enableThumbnails.set}
|
||||||
enableAutoplay={state.enableAutoplay.state}
|
enableAutoplay={state.enableAutoplay.state}
|
||||||
setEnableAutoplay={state.enableAutoplay.set}
|
setEnableAutoplay={state.enableAutoplay.set}
|
||||||
|
enableSkipCredits={state.enableSkipCredits.state}
|
||||||
|
setEnableSkipCredits={state.enableSkipCredits.set}
|
||||||
sourceOrder={availableSources}
|
sourceOrder={availableSources}
|
||||||
setSourceOrder={state.sourceOrder.set}
|
setSourceOrder={state.sourceOrder.set}
|
||||||
enableSourceOrder={state.enableSourceOrder.state}
|
enableSourceOrder={state.enableSourceOrder.state}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@ export function PreferencesPart(props: {
|
||||||
setEnableThumbnails: (v: boolean) => void;
|
setEnableThumbnails: (v: boolean) => void;
|
||||||
enableAutoplay: boolean;
|
enableAutoplay: boolean;
|
||||||
setEnableAutoplay: (v: boolean) => void;
|
setEnableAutoplay: (v: boolean) => void;
|
||||||
|
enableSkipCredits: boolean;
|
||||||
|
setEnableSkipCredits: (v: boolean) => void;
|
||||||
sourceOrder: string[];
|
sourceOrder: string[];
|
||||||
setSourceOrder: (v: string[]) => void;
|
setSourceOrder: (v: string[]) => void;
|
||||||
enableSourceOrder: boolean;
|
enableSourceOrder: boolean;
|
||||||
|
|
@ -122,6 +124,29 @@ export function PreferencesPart(props: {
|
||||||
{t("settings.preferences.autoplayLabel")}
|
{t("settings.preferences.autoplayLabel")}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Skip End Credits Preference */}
|
||||||
|
{props.enableAutoplay && allowAutoplay && (
|
||||||
|
<div className="pt-4">
|
||||||
|
<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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import { immer } from "zustand/middleware/immer";
|
||||||
export interface PreferencesStore {
|
export interface PreferencesStore {
|
||||||
enableThumbnails: boolean;
|
enableThumbnails: boolean;
|
||||||
enableAutoplay: boolean;
|
enableAutoplay: boolean;
|
||||||
|
enableSkipCredits: boolean;
|
||||||
enableDiscover: boolean;
|
enableDiscover: boolean;
|
||||||
enablePopDetails: boolean;
|
enablePopDetails: boolean;
|
||||||
sourceOrder: string[];
|
sourceOrder: string[];
|
||||||
|
|
@ -13,6 +14,7 @@ export interface PreferencesStore {
|
||||||
|
|
||||||
setEnableThumbnails(v: boolean): void;
|
setEnableThumbnails(v: boolean): void;
|
||||||
setEnableAutoplay(v: boolean): void;
|
setEnableAutoplay(v: boolean): void;
|
||||||
|
setEnableSkipCredits(v: boolean): void;
|
||||||
setEnableDiscover(v: boolean): void;
|
setEnableDiscover(v: boolean): void;
|
||||||
setEnablePopDetails(v: boolean): void;
|
setEnablePopDetails(v: boolean): void;
|
||||||
setSourceOrder(v: string[]): void;
|
setSourceOrder(v: string[]): void;
|
||||||
|
|
@ -25,6 +27,7 @@ export const usePreferencesStore = create(
|
||||||
immer<PreferencesStore>((set) => ({
|
immer<PreferencesStore>((set) => ({
|
||||||
enableThumbnails: false,
|
enableThumbnails: false,
|
||||||
enableAutoplay: true,
|
enableAutoplay: true,
|
||||||
|
enableSkipCredits: true,
|
||||||
enableDiscover: true,
|
enableDiscover: true,
|
||||||
enablePopDetails: false,
|
enablePopDetails: false,
|
||||||
sourceOrder: [],
|
sourceOrder: [],
|
||||||
|
|
@ -40,6 +43,11 @@ export const usePreferencesStore = create(
|
||||||
s.enableAutoplay = v;
|
s.enableAutoplay = v;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
setEnableSkipCredits(v) {
|
||||||
|
set((s) => {
|
||||||
|
s.enableSkipCredits = v;
|
||||||
|
});
|
||||||
|
},
|
||||||
setEnableDiscover(v) {
|
setEnableDiscover(v) {
|
||||||
set((s) => {
|
set((s) => {
|
||||||
s.enableDiscover = v;
|
s.enableDiscover = v;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue