diff --git a/src/components/player/atoms/NextEpisodeButton.tsx b/src/components/player/atoms/NextEpisodeButton.tsx
index 07d89068..75ef65b0 100644
--- a/src/components/player/atoms/NextEpisodeButton.tsx
+++ b/src/components/player/atoms/NextEpisodeButton.tsx
@@ -1,17 +1,15 @@
import classNames from "classnames";
-import { useCallback, useEffect } from "react";
+import { useCallback, useEffect, useRef } from "react";
import { useTranslation } from "react-i18next";
-import { isExtensionActiveCached } from "@/backend/extension/messaging";
import { Icon, Icons } from "@/components/Icon";
import { usePlayerMeta } from "@/components/player/hooks/usePlayerMeta";
import { Transition } from "@/components/utils/Transition";
-import { conf } from "@/setup/config";
-import { useAuthStore } from "@/stores/auth";
import { PlayerMeta } from "@/stores/player/slices/source";
import { usePlayerStore } from "@/stores/player/store";
import { usePreferencesStore } from "@/stores/preferences";
import { useProgressStore } from "@/stores/progress";
+import { isAutoplayAllowed } from "@/utils/autoplay";
function shouldShowNextEpisodeButton(
time: number,
@@ -64,6 +62,7 @@ export function NextEpisodeButton(props: {
const enableAutoplay = usePreferencesStore((s) => s.enableAutoplay);
let show = false;
+ const hasAutoplayed = useRef(false);
if (showingState === "always") show = true;
else if (showingState === "hover" && props.controlsShowing) show = true;
if (isHidden || status !== "playing" || duration === 0) show = false;
@@ -102,21 +101,14 @@ export function NextEpisodeButton(props: {
useEffect(() => {
if (!enableAutoplay || metaType !== "show") return;
+ const onePercent = duration / 100;
+ const isEnding = time >= duration - onePercent && duration !== 0;
- const interval = setInterval(() => {
- const onePercent = duration / 100;
- const isEnding = time >= duration - onePercent && duration !== 0;
-
- const allowAutoplay = Boolean(
- conf().ALLOW_AUTOPLAY ||
- isExtensionActiveCached() ||
- useAuthStore.getState().proxySet,
- );
-
- if (isEnding && allowAutoplay) loadNextEpisode();
- }, 250);
-
- return () => clearInterval(interval);
+ if (duration === 0) hasAutoplayed.current = false;
+ if (isEnding && isAutoplayAllowed() && !hasAutoplayed.current) {
+ hasAutoplayed.current = true;
+ loadNextEpisode();
+ }
}, [duration, enableAutoplay, loadNextEpisode, metaType, time]);
if (!meta?.episode || !nextEp) return null;
diff --git a/src/pages/parts/settings/PreferencesPart.tsx b/src/pages/parts/settings/PreferencesPart.tsx
index f81e0c9e..efead293 100644
--- a/src/pages/parts/settings/PreferencesPart.tsx
+++ b/src/pages/parts/settings/PreferencesPart.tsx
@@ -1,28 +1,14 @@
+import classNames from "classnames";
import { useTranslation } from "react-i18next";
-import { useAsync } from "react-use";
-import { isExtensionActive } from "@/backend/extension/messaging";
import { Toggle } from "@/components/buttons/Toggle";
import { FlagIcon } from "@/components/FlagIcon";
import { Dropdown } from "@/components/form/Dropdown";
import { Heading1 } from "@/components/utils/Text";
-import { conf } from "@/setup/config";
import { appLanguageOptions } from "@/setup/i18n";
-import { useAuthStore } from "@/stores/auth";
+import { isAutoplayAllowed } from "@/utils/autoplay";
import { getLocaleInfo, sortLangCodes } from "@/utils/language";
-function useIsExtensionActive() {
- const { loading, value } = useAsync(async () => {
- const extensionStatus = (await isExtensionActive()) ? "success" : "unset";
- return extensionStatus === "success";
- }, []);
-
- return {
- loading,
- active: value,
- };
-}
-
export function PreferencesPart(props: {
language: string;
setLanguage: (l: string) => void;
@@ -33,14 +19,8 @@ export function PreferencesPart(props: {
}) {
const { t } = useTranslation();
const sorted = sortLangCodes(appLanguageOptions.map((item) => item.code));
- const { loading, active } = useIsExtensionActive();
- const extensionActive = active && !loading;
- const allowAutoplay = Boolean(
- conf().ALLOW_AUTOPLAY ||
- extensionActive ||
- useAuthStore.getState().proxySet,
- );
+ const allowAutoplay = isAutoplayAllowed();
const options = appLanguageOptions
.sort((a, b) => sorted.indexOf(a.code) - sorted.indexOf(b.code))
@@ -101,12 +81,12 @@ export function PreferencesPart(props: {
? props.setEnableAutoplay(!props.enableAutoplay)
: null
}
- 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"
- style={{
- pointerEvents: allowAutoplay ? "auto" : "none",
- opacity: allowAutoplay ? 1 : 0.5,
- cursor: allowAutoplay ? "pointer" : "not-allowed",
- }}
+ 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 ? "cursor-pointer" : "cursor-not-allowed",
+ allowAutoplay ? "opacity-100" : "opacity-50",
+ allowAutoplay ? "pointer-events-auto" : "pointer-events-none",
+ )}
>
diff --git a/src/utils/autoplay.ts b/src/utils/autoplay.ts new file mode 100644 index 00000000..aee01ffb --- /dev/null +++ b/src/utils/autoplay.ts @@ -0,0 +1,11 @@ +import { isExtensionActiveCached } from "@/backend/extension/messaging"; +import { conf } from "@/setup/config"; +import { useAuthStore } from "@/stores/auth"; + +export function isAutoplayAllowed() { + return Boolean( + conf().ALLOW_AUTOPLAY || + isExtensionActiveCached() || + useAuthStore.getState().proxySet, + ); +}