This commit is contained in:
Cooper Ransom 2024-03-27 17:50:37 -04:00
parent 5fb0a32456
commit 36a92dabe1
5 changed files with 36 additions and 237 deletions

View file

@ -21,8 +21,8 @@ import {
ExtensionDetectionResult,
detectExtensionInstall,
} from "@/utils/detectFeatures";
import { getExtensionState } from "@/utils/onboarding";
import type { ExtensionStatus } from "@/utils/onboarding";
import { getExtensionState } from "@/utils/extension";
import type { ExtensionStatus } from "@/utils/extension";
function RefreshBar() {
const { t } = useTranslation();

View file

@ -11,7 +11,8 @@ import { Paragraph } from "@/components/text/Paragraph";
import { Title } from "@/components/text/Title";
import { ScrapingItems, ScrapingSegment } from "@/hooks/useProviderScrape";
import { ErrorContainer, ErrorLayout } from "@/pages/layouts/ErrorLayout";
import { ExtensionStatus, getExtensionState } from "@/utils/onboarding";
import { getExtensionState } from "@/utils/extension";
import type { ExtensionStatus } from "@/utils/extension";
import { getProviderApiUrls } from "@/utils/proxyUrls";
import { ErrorCardInModal } from "../errors/ErrorCard";
@ -29,8 +30,6 @@ export function ScrapeErrorPart(props: ScrapeErrorPartProps) {
const location = useLocation();
const [extensionState, setExtensionState] =
useState<ExtensionStatus>("unknown");
const [title, setTitle] = useState(t("player.scraping.notFound.title"));
const [icon, setIcon] = useState(Icons.WAND);
const error = useMemo(() => {
const data = props.data;
@ -51,10 +50,6 @@ export function ScrapeErrorPart(props: ScrapeErrorPartProps) {
useEffect(() => {
getExtensionState().then((state: ExtensionStatus) => {
setExtensionState(state);
if (state === "disallowed") {
setTitle(t("player.scraping.extensionFailure.disabledTitle"));
setIcon(Icons.LOCK);
}
});
}, [t]);
@ -62,8 +57,10 @@ export function ScrapeErrorPart(props: ScrapeErrorPartProps) {
return (
<ErrorLayout>
<ErrorContainer>
<IconPill icon={icon}>{t("player.scraping.notFound.badge")}</IconPill>
<Title>{title}</Title>
<IconPill icon={Icons.LOCK}>
{t("player.scraping.notFound.badge")}
</IconPill>
<Title>{t("player.scraping.extensionFailure.disabledTitle")}</Title>
<Paragraph>
<Trans
i18nKey="player.scraping.extensionFailure.text"
@ -81,7 +78,7 @@ export function ScrapeErrorPart(props: ScrapeErrorPartProps) {
padding="md:px-12 p-2.5"
className="mt-6"
>
{t("player.scraping.notFound.homeButton")}
{t("player.scraping.extensionFailure.homeButton")}
</Button>
<Button
onClick={() => {
@ -98,13 +95,6 @@ export function ScrapeErrorPart(props: ScrapeErrorPartProps) {
</Button>
</div>
</ErrorContainer>
{error ? (
<ErrorCardInModal
id={modal.id}
onClose={() => modal.hide()}
error={error}
/>
) : null}
</ErrorLayout>
);
}
@ -112,16 +102,11 @@ export function ScrapeErrorPart(props: ScrapeErrorPartProps) {
return (
<ErrorLayout>
<ErrorContainer>
<IconPill icon={icon}>{t("player.scraping.notFound.badge")}</IconPill>
<Title>{title}</Title>
<Paragraph>
<Trans
i18nKey="player.scraping.notFound.text"
components={{
bold: <span className="font-bold" style={{ color: "#cfcfcf" }} />,
}}
/>
</Paragraph>
<IconPill icon={Icons.WAND}>
{t("player.scraping.notFound.badge")}
</IconPill>
<Title>{t("player.scraping.notFound.title")}</Title>
<Paragraph>{t("player.scraping.notFound.text")}</Paragraph>
<div className="flex gap-3">
<Button
href="/"
@ -132,12 +117,7 @@ export function ScrapeErrorPart(props: ScrapeErrorPartProps) {
{t("player.scraping.notFound.homeButton")}
</Button>
<Button
onClick={() => {
sendPage({
page: "PermissionGrant",
redirectUrl: window.location.href,
});
}}
onClick={() => modal.show()}
theme="purple"
padding="md:px-12 p-2.5"
className="mt-6"

20
src/utils/extension.ts Normal file
View file

@ -0,0 +1,20 @@
import { isAllowedExtensionVersion } from "@/backend/extension/compatibility";
import { extensionInfo } from "@/backend/extension/messaging";
export type ExtensionStatus =
| "unknown"
| "failed"
| "disallowed"
| "noperms"
| "outdated"
| "success";
export async function getExtensionState(): Promise<ExtensionStatus> {
const info = await extensionInfo();
if (!info) return "unknown"; // cant talk to extension
if (!info.success) return "failed"; // extension failed to respond
if (!info.allowed) return "disallowed"; // extension is not enabled on this page
if (!info.hasPermission) return "noperms"; // extension has no perms to do it's tasks
if (!isAllowedExtensionVersion(info.version)) return "outdated"; // extension is too old
return "success"; // no problems
}

View file

@ -1,30 +1,8 @@
import { isAllowedExtensionVersion } from "@/backend/extension/compatibility";
import {
extensionInfo,
isExtensionActive,
} from "@/backend/extension/messaging";
import { isExtensionActive } from "@/backend/extension/messaging";
import { conf } from "@/setup/config";
import { useAuthStore } from "@/stores/auth";
import { useOnboardingStore } from "@/stores/onboarding";
export type ExtensionStatus =
| "unknown"
| "failed"
| "disallowed"
| "noperms"
| "outdated"
| "success";
export async function getExtensionState(): Promise<ExtensionStatus> {
const info = await extensionInfo();
if (!info) return "unknown"; // cant talk to extension
if (!info.success) return "failed"; // extension failed to respond
if (!info.allowed) return "disallowed"; // extension is not enabled on this page
if (!info.hasPermission) return "noperms"; // extension has no perms to do it's tasks
if (!isAllowedExtensionVersion(info.version)) return "outdated"; // extension is too old
return "success"; // no problems
}
export async function needsOnboarding(): Promise<boolean> {
// if onboarding is dislabed, no onboarding needed
if (!conf().HAS_ONBOARDING) return false;

View file

@ -1,179 +0,0 @@
import { ReactElement, Suspense, lazy, useEffect, useState } from "react";
import { lazyWithPreload } from "react-lazy-with-preload";
import {
Navigate,
Route,
Routes,
useLocation,
useNavigate,
useParams,
} from "react-router-dom";
import { convertLegacyUrl, isLegacyUrl } from "@/backend/metadata/getmeta";
import { generateQuickSearchMediaUrl } from "@/backend/metadata/tmdb";
import { useOnlineListener } from "@/hooks/usePing";
import { AboutPage } from "@/pages/About";
import { AdminPage } from "@/pages/admin/AdminPage";
import VideoTesterView from "@/pages/developer/VideoTesterView";
import { DmcaPage, shouldHaveDmcaPage } from "@/pages/Dmca";
import MaintenancePage from "@/pages/errors/MaintenancePage";
import { NotFoundPage } from "@/pages/errors/NotFoundPage";
import { HomePage } from "@/pages/HomePage";
import { LoginPage } from "@/pages/Login";
import { OnboardingPage } from "@/pages/onboarding/Onboarding";
import { OnboardingExtensionPage } from "@/pages/onboarding/OnboardingExtension";
import { OnboardingProxyPage } from "@/pages/onboarding/OnboardingProxy";
import { RegisterPage } from "@/pages/Register";
import { SupportPage } from "@/pages/Support";
import { Layout } from "@/setup/Layout";
import { useHistoryListener } from "@/stores/history";
import { LanguageProvider } from "@/stores/language";
const DeveloperPage = lazy(() => import("@/pages/DeveloperPage"));
const TestView = lazy(() => import("@/pages/developer/TestView"));
const PlayerView = lazyWithPreload(() => import("@/pages/PlayerView"));
const SettingsPage = lazyWithPreload(() => import("@/pages/Settings"));
PlayerView.preload();
SettingsPage.preload();
function LegacyUrlView({ children }: { children: ReactElement }) {
const location = useLocation();
const navigate = useNavigate();
useEffect(() => {
const url = location.pathname;
if (!isLegacyUrl(url)) return;
convertLegacyUrl(location.pathname).then((convertedUrl) => {
navigate(convertedUrl ?? "/", { replace: true });
});
}, [location.pathname, navigate]);
if (isLegacyUrl(location.pathname)) return null;
return children;
}
function QuickSearch() {
const { query } = useParams<{ query: string }>();
const navigate = useNavigate();
useEffect(() => {
if (query) {
generateQuickSearchMediaUrl(query).then((url) => {
navigate(url ?? "/", { replace: true });
});
} else {
navigate("/", { replace: true });
}
}, [query, navigate]);
return null;
}
function QueryView() {
const { query } = useParams<{ query: string }>();
const navigate = useNavigate();
useEffect(() => {
if (query) {
navigate(`/browse/${query}`, { replace: true });
} else {
navigate("/", { replace: true });
}
}, [query, navigate]);
return null;
}
// Duplicate of @/src/setup/App.tsx
function App() {
useHistoryListener();
useOnlineListener();
const maintenance = false; // Changing to true shows maintenance page
const [showDowntime, setShowDowntime] = useState(maintenance);
const handleButtonClick = () => {
setShowDowntime(false);
};
useEffect(() => {
const sessionToken = sessionStorage.getItem("downtimeToken");
if (!sessionToken && maintenance) {
setShowDowntime(true);
sessionStorage.setItem("downtimeToken", "true");
}
}, [setShowDowntime, maintenance]);
return (
<Layout>
<LanguageProvider />
{!showDowntime && (
<Routes>
{/* functional routes */}
<Route path="/s/:query" element={<QuickSearch />} />
<Route path="/search/:type" element={<Navigate to="/browse" />} />
<Route path="/search/:type/:query?" element={<QueryView />} />
{/* pages */}
<Route
path="/media/:media"
element={
<LegacyUrlView>
<Suspense fallback={null}>
<PlayerView />
</Suspense>
</LegacyUrlView>
}
/>
<Route
path="/media/:media/:season/:episode"
element={
<LegacyUrlView>
<Suspense fallback={null}>
<PlayerView />
</Suspense>
</LegacyUrlView>
}
/>
<Route path="/browse/:query?" element={<HomePage />} />
<Route path="/" element={<HomePage />} />
<Route path="/register" element={<RegisterPage />} />
<Route path="/login" element={<LoginPage />} />
<Route path="/about" element={<AboutPage />} />
<Route path="/onboarding" element={<OnboardingPage />} />
<Route
path="/onboarding/extension"
element={<OnboardingExtensionPage />}
/>
<Route path="/onboarding/proxy" element={<OnboardingProxyPage />} />
{shouldHaveDmcaPage() ? (
<Route path="/dmca" element={<DmcaPage />} />
) : null}
{/* Support page */}
<Route path="/support" element={<SupportPage />} />
{/* Settings page */}
<Route
path="/settings"
element={
<Suspense fallback={null}>
<SettingsPage />
</Suspense>
}
/>
{/* admin routes */}
<Route path="/admin" element={<AdminPage />} />
{/* other */}
<Route path="/dev" element={<DeveloperPage />} />
<Route path="/dev/video" element={<VideoTesterView />} />
{/* developer routes that can abuse workers are disabled in production */}
{process.env.NODE_ENV === "development" ? (
<Route path="/dev/test" element={<TestView />} />
) : null}
<Route path="*" element={<NotFoundPage />} />
</Routes>
)}
{showDowntime && (
<MaintenancePage onHomeButtonClick={handleButtonClick} />
)}
</Layout>
);
}