mirror of
https://github.com/p-stream/p-stream.git
synced 2026-04-21 05:52:25 +00:00
Silly me
This commit is contained in:
parent
5fb0a32456
commit
36a92dabe1
5 changed files with 36 additions and 237 deletions
|
|
@ -21,8 +21,8 @@ import {
|
||||||
ExtensionDetectionResult,
|
ExtensionDetectionResult,
|
||||||
detectExtensionInstall,
|
detectExtensionInstall,
|
||||||
} from "@/utils/detectFeatures";
|
} from "@/utils/detectFeatures";
|
||||||
import { getExtensionState } from "@/utils/onboarding";
|
import { getExtensionState } from "@/utils/extension";
|
||||||
import type { ExtensionStatus } from "@/utils/onboarding";
|
import type { ExtensionStatus } from "@/utils/extension";
|
||||||
|
|
||||||
function RefreshBar() {
|
function RefreshBar() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,8 @@ import { Paragraph } from "@/components/text/Paragraph";
|
||||||
import { Title } from "@/components/text/Title";
|
import { Title } from "@/components/text/Title";
|
||||||
import { ScrapingItems, ScrapingSegment } from "@/hooks/useProviderScrape";
|
import { ScrapingItems, ScrapingSegment } from "@/hooks/useProviderScrape";
|
||||||
import { ErrorContainer, ErrorLayout } from "@/pages/layouts/ErrorLayout";
|
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 { getProviderApiUrls } from "@/utils/proxyUrls";
|
||||||
|
|
||||||
import { ErrorCardInModal } from "../errors/ErrorCard";
|
import { ErrorCardInModal } from "../errors/ErrorCard";
|
||||||
|
|
@ -29,8 +30,6 @@ export function ScrapeErrorPart(props: ScrapeErrorPartProps) {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const [extensionState, setExtensionState] =
|
const [extensionState, setExtensionState] =
|
||||||
useState<ExtensionStatus>("unknown");
|
useState<ExtensionStatus>("unknown");
|
||||||
const [title, setTitle] = useState(t("player.scraping.notFound.title"));
|
|
||||||
const [icon, setIcon] = useState(Icons.WAND);
|
|
||||||
|
|
||||||
const error = useMemo(() => {
|
const error = useMemo(() => {
|
||||||
const data = props.data;
|
const data = props.data;
|
||||||
|
|
@ -51,10 +50,6 @@ export function ScrapeErrorPart(props: ScrapeErrorPartProps) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getExtensionState().then((state: ExtensionStatus) => {
|
getExtensionState().then((state: ExtensionStatus) => {
|
||||||
setExtensionState(state);
|
setExtensionState(state);
|
||||||
if (state === "disallowed") {
|
|
||||||
setTitle(t("player.scraping.extensionFailure.disabledTitle"));
|
|
||||||
setIcon(Icons.LOCK);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}, [t]);
|
}, [t]);
|
||||||
|
|
||||||
|
|
@ -62,8 +57,10 @@ export function ScrapeErrorPart(props: ScrapeErrorPartProps) {
|
||||||
return (
|
return (
|
||||||
<ErrorLayout>
|
<ErrorLayout>
|
||||||
<ErrorContainer>
|
<ErrorContainer>
|
||||||
<IconPill icon={icon}>{t("player.scraping.notFound.badge")}</IconPill>
|
<IconPill icon={Icons.LOCK}>
|
||||||
<Title>{title}</Title>
|
{t("player.scraping.notFound.badge")}
|
||||||
|
</IconPill>
|
||||||
|
<Title>{t("player.scraping.extensionFailure.disabledTitle")}</Title>
|
||||||
<Paragraph>
|
<Paragraph>
|
||||||
<Trans
|
<Trans
|
||||||
i18nKey="player.scraping.extensionFailure.text"
|
i18nKey="player.scraping.extensionFailure.text"
|
||||||
|
|
@ -81,7 +78,7 @@ export function ScrapeErrorPart(props: ScrapeErrorPartProps) {
|
||||||
padding="md:px-12 p-2.5"
|
padding="md:px-12 p-2.5"
|
||||||
className="mt-6"
|
className="mt-6"
|
||||||
>
|
>
|
||||||
{t("player.scraping.notFound.homeButton")}
|
{t("player.scraping.extensionFailure.homeButton")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
@ -98,13 +95,6 @@ export function ScrapeErrorPart(props: ScrapeErrorPartProps) {
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</ErrorContainer>
|
</ErrorContainer>
|
||||||
{error ? (
|
|
||||||
<ErrorCardInModal
|
|
||||||
id={modal.id}
|
|
||||||
onClose={() => modal.hide()}
|
|
||||||
error={error}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
</ErrorLayout>
|
</ErrorLayout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -112,16 +102,11 @@ export function ScrapeErrorPart(props: ScrapeErrorPartProps) {
|
||||||
return (
|
return (
|
||||||
<ErrorLayout>
|
<ErrorLayout>
|
||||||
<ErrorContainer>
|
<ErrorContainer>
|
||||||
<IconPill icon={icon}>{t("player.scraping.notFound.badge")}</IconPill>
|
<IconPill icon={Icons.WAND}>
|
||||||
<Title>{title}</Title>
|
{t("player.scraping.notFound.badge")}
|
||||||
<Paragraph>
|
</IconPill>
|
||||||
<Trans
|
<Title>{t("player.scraping.notFound.title")}</Title>
|
||||||
i18nKey="player.scraping.notFound.text"
|
<Paragraph>{t("player.scraping.notFound.text")}</Paragraph>
|
||||||
components={{
|
|
||||||
bold: <span className="font-bold" style={{ color: "#cfcfcf" }} />,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Paragraph>
|
|
||||||
<div className="flex gap-3">
|
<div className="flex gap-3">
|
||||||
<Button
|
<Button
|
||||||
href="/"
|
href="/"
|
||||||
|
|
@ -132,12 +117,7 @@ export function ScrapeErrorPart(props: ScrapeErrorPartProps) {
|
||||||
{t("player.scraping.notFound.homeButton")}
|
{t("player.scraping.notFound.homeButton")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => modal.show()}
|
||||||
sendPage({
|
|
||||||
page: "PermissionGrant",
|
|
||||||
redirectUrl: window.location.href,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
theme="purple"
|
theme="purple"
|
||||||
padding="md:px-12 p-2.5"
|
padding="md:px-12 p-2.5"
|
||||||
className="mt-6"
|
className="mt-6"
|
||||||
|
|
|
||||||
20
src/utils/extension.ts
Normal file
20
src/utils/extension.ts
Normal 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
|
||||||
|
}
|
||||||
|
|
@ -1,30 +1,8 @@
|
||||||
import { isAllowedExtensionVersion } from "@/backend/extension/compatibility";
|
import { isExtensionActive } from "@/backend/extension/messaging";
|
||||||
import {
|
|
||||||
extensionInfo,
|
|
||||||
isExtensionActive,
|
|
||||||
} from "@/backend/extension/messaging";
|
|
||||||
import { conf } from "@/setup/config";
|
import { conf } from "@/setup/config";
|
||||||
import { useAuthStore } from "@/stores/auth";
|
import { useAuthStore } from "@/stores/auth";
|
||||||
import { useOnboardingStore } from "@/stores/onboarding";
|
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> {
|
export async function needsOnboarding(): Promise<boolean> {
|
||||||
// if onboarding is dislabed, no onboarding needed
|
// if onboarding is dislabed, no onboarding needed
|
||||||
if (!conf().HAS_ONBOARDING) return false;
|
if (!conf().HAS_ONBOARDING) return false;
|
||||||
|
|
|
||||||
|
|
@ -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>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Loading…
Reference in a new issue