mirror of
https://github.com/sussy-code/smov.git
synced 2024-12-20 14:37:43 +01:00
Detect browser for extension
This commit is contained in:
parent
8abcd6c43a
commit
e1c09225ee
5 changed files with 168 additions and 30 deletions
|
@ -38,6 +38,7 @@
|
|||
"@types/node-forge": "^1.3.10",
|
||||
"classnames": "^2.3.2",
|
||||
"core-js": "^3.34.0",
|
||||
"detect-browser": "^5.3.0",
|
||||
"dompurify": "^3.0.6",
|
||||
"flag-icons": "^7.1.0",
|
||||
"focus-trap-react": "^10.2.3",
|
||||
|
|
|
@ -48,6 +48,9 @@ dependencies:
|
|||
core-js:
|
||||
specifier: ^3.34.0
|
||||
version: 3.34.0
|
||||
detect-browser:
|
||||
specifier: ^5.3.0
|
||||
version: 5.3.0
|
||||
dompurify:
|
||||
specifier: ^3.0.6
|
||||
version: 3.0.6
|
||||
|
@ -3338,6 +3341,10 @@ packages:
|
|||
resolution: {integrity: sha512-M1Ob1zPSIvlARiJUkKqvAZ3VAqQY6Jcuth/pBKQ2b1dX/Qx0OnJ8Vux6J2H5PTMQeRzWrrbTu70VxBfv/OPDJA==}
|
||||
dev: false
|
||||
|
||||
/detect-browser@5.3.0:
|
||||
resolution: {integrity: sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==}
|
||||
dev: false
|
||||
|
||||
/didyoumean@1.2.2:
|
||||
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
|
||||
dev: true
|
||||
|
|
|
@ -232,7 +232,7 @@
|
|||
"downloadSubtitle": "Download current subtitle",
|
||||
"downloadPlaylist": "Download playlist",
|
||||
"downloadVideo": "Download video",
|
||||
"hlsDisclaimer": "Downloads are taken directly from the provider. movie-web does not have control over how the downloads are provided.<br /><br />Please note that you are downloading an HLS playlist, it is <bold>not recommended to download if you are not familiar with advanced streaming formats</bold>. Try different sources for different formats.",
|
||||
"hlsDisclaimer": "Downloads are taken directly from the provider. movie-web does not have control over how the downloads are provided.<br /><br />Please note that you are downloading an HLS playlist, <bold>it is not recommended to download if you are not familiar with advanced streaming formats</bold>. Try different sources for different formats.",
|
||||
"onAndroid": {
|
||||
"1": "To download on Android, click the download button then, on the new page, <bold>tap and hold</bold> on the video, then select <bold>save</bold>.",
|
||||
"shortTitle": "Download / Android",
|
||||
|
@ -506,8 +506,10 @@
|
|||
"extension": {
|
||||
"title": "Let's start with an extension",
|
||||
"explainer": "Using the browser extension, you can get the best streams we have to offer. With just a simple install.",
|
||||
"explainerIos": "Unfortunately, the browser extension is not supported on IOS, Press <bold>Go back</bold> to choose another option.",
|
||||
"extensionHelp": "If you've installed the extension but it's not detected. <bold>Open the extension through your browsers extension menu</bold> and follow the steps on screen.",
|
||||
"link": "Install extension",
|
||||
"linkChrome": "Install Chrome extension",
|
||||
"linkFirefox": "Install Firefox extension",
|
||||
"back": "Go back",
|
||||
"status": {
|
||||
"loading": "Waiting for you to install the extension",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { ReactNode } from "react";
|
||||
import { ReactNode, useMemo } from "react";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
import { useAsyncFn, useInterval } from "react-use";
|
||||
|
||||
|
@ -18,6 +18,10 @@ import {
|
|||
import { Card, Link } from "@/pages/onboarding/utils";
|
||||
import { PageTitle } from "@/pages/parts/util/PageTitle";
|
||||
import { conf } from "@/setup/config";
|
||||
import {
|
||||
ExtensionDetectionResult,
|
||||
detectExtensionInstall,
|
||||
} from "@/utils/detectFeatures";
|
||||
|
||||
type ExtensionStatus =
|
||||
| "unknown"
|
||||
|
@ -40,6 +44,7 @@ async function getExtensionState(): Promise<ExtensionStatus> {
|
|||
export function ExtensionStatus(props: {
|
||||
status: ExtensionStatus;
|
||||
loading: boolean;
|
||||
showHelp?: boolean;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
|
@ -88,19 +93,119 @@ export function ExtensionStatus(props: {
|
|||
{content}
|
||||
</div>
|
||||
</Card>
|
||||
<Card className="mt-4">
|
||||
<div className="flex items-center space-x-7">
|
||||
<Icon icon={Icons.WARNING} className="text-type-danger text-2xl" />
|
||||
<p className="flex-1">
|
||||
<Trans
|
||||
i18nKey="onboarding.extension.extensionHelp"
|
||||
components={{
|
||||
bold: <span className="text-white" />,
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</Card>
|
||||
{props.showHelp ? (
|
||||
<Card className="mt-4">
|
||||
<div className="flex items-center space-x-7">
|
||||
<Icon icon={Icons.WARNING} className="text-type-danger text-2xl" />
|
||||
<p className="flex-1">
|
||||
<Trans
|
||||
i18nKey="onboarding.extension.extensionHelp"
|
||||
components={{
|
||||
bold: <span className="text-white" />,
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</Card>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
interface ExtensionPageProps {
|
||||
status: ExtensionStatus;
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
function ChromeExtensionPage(props: ExtensionPageProps) {
|
||||
const { t } = useTranslation();
|
||||
const installLink = conf().ONBOARDING_EXTENSION_INSTALL_LINK;
|
||||
return (
|
||||
<>
|
||||
<Heading2 className="!mt-0 !text-3xl max-w-[435px]">
|
||||
{t("onboarding.extension.title")}
|
||||
</Heading2>
|
||||
<Paragraph className="max-w-[320px] mb-4">
|
||||
{t("onboarding.extension.explainer")}
|
||||
</Paragraph>
|
||||
{installLink ? (
|
||||
<Link href={installLink} target="_blank" className="mb-12">
|
||||
{t("onboarding.extension.linkChrome")}
|
||||
</Link>
|
||||
) : null}
|
||||
|
||||
<ExtensionStatus status={props.status} loading={props.loading} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function FirefoxExtensionPage(props: ExtensionPageProps) {
|
||||
const { t } = useTranslation();
|
||||
const installLink = conf().ONBOARDING_EXTENSION_INSTALL_LINK;
|
||||
return (
|
||||
<>
|
||||
<Heading2 className="!mt-0 !text-3xl max-w-[435px]">
|
||||
{t("onboarding.extension.title")}
|
||||
</Heading2>
|
||||
<Paragraph className="max-w-[320px] mb-4">
|
||||
{t("onboarding.extension.explainer")}
|
||||
</Paragraph>
|
||||
{installLink ? (
|
||||
<Link href={installLink} target="_blank" className="mb-12">
|
||||
{t("onboarding.extension.linkFirefox")}
|
||||
</Link>
|
||||
) : null}
|
||||
|
||||
<ExtensionStatus status={props.status} loading={props.loading} showHelp />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function IosExtensionPage(_props: ExtensionPageProps) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<>
|
||||
<Heading2 className="!mt-0 !text-3xl max-w-[435px]">
|
||||
{t("onboarding.extension.title")}
|
||||
</Heading2>
|
||||
<Paragraph className="max-w-[320px] mb-4">
|
||||
<Trans
|
||||
i18nKey="onboarding.extension.explainerIos"
|
||||
components={{ bold: <span className="text-white font-bold" /> }}
|
||||
/>
|
||||
</Paragraph>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function UnknownExtensionPage(props: ExtensionPageProps) {
|
||||
const { t } = useTranslation();
|
||||
const installChromeLink = conf().ONBOARDING_EXTENSION_INSTALL_LINK;
|
||||
const installFirefoxLink = conf().ONBOARDING_EXTENSION_INSTALL_LINK;
|
||||
return (
|
||||
<>
|
||||
<Heading2 className="!mt-0 !text-3xl max-w-[435px]">
|
||||
{t("onboarding.extension.title")}
|
||||
</Heading2>
|
||||
<Paragraph className="max-w-[320px] mb-4">
|
||||
{t("onboarding.extension.explainer")}
|
||||
</Paragraph>
|
||||
<div className="mb-4">
|
||||
{installChromeLink ? (
|
||||
<Link href={installChromeLink} target="_blank">
|
||||
{t("onboarding.extension.linkChrome")}
|
||||
</Link>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="mb-12">
|
||||
{installFirefoxLink ? (
|
||||
<Link href={installFirefoxLink} target="_blank">
|
||||
{t("onboarding.extension.linkFirefox")}
|
||||
</Link>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
<ExtensionStatus status={props.status} loading={props.loading} showHelp />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -109,7 +214,7 @@ export function OnboardingExtensionPage() {
|
|||
const { t } = useTranslation();
|
||||
const navigate = useNavigateOnboarding();
|
||||
const { completeAndRedirect } = useRedirectBack();
|
||||
const installLink = conf().ONBOARDING_EXTENSION_INSTALL_LINK;
|
||||
const extensionSupport = useMemo(() => detectExtensionInstall(), []);
|
||||
|
||||
const [{ loading, value }, exec] = useAsyncFn(
|
||||
async (triggeredManually: boolean = false) => {
|
||||
|
@ -121,24 +226,23 @@ export function OnboardingExtensionPage() {
|
|||
);
|
||||
useInterval(exec, 1000);
|
||||
|
||||
const componentMap: Record<
|
||||
ExtensionDetectionResult,
|
||||
typeof UnknownExtensionPage
|
||||
> = {
|
||||
chrome: ChromeExtensionPage,
|
||||
firefox: FirefoxExtensionPage,
|
||||
ios: IosExtensionPage,
|
||||
unknown: UnknownExtensionPage,
|
||||
};
|
||||
const PageContent = componentMap[extensionSupport];
|
||||
|
||||
return (
|
||||
<MinimalPageLayout>
|
||||
<PageTitle subpage k="global.pages.onboarding" />
|
||||
<CenterContainer>
|
||||
<Stepper steps={2} current={2} className="mb-12" />
|
||||
<Heading2 className="!mt-0 !text-3xl max-w-[435px]">
|
||||
{t("onboarding.extension.title")}
|
||||
</Heading2>
|
||||
<Paragraph className="max-w-[320px] mb-4">
|
||||
{t("onboarding.extension.explainer")}
|
||||
</Paragraph>
|
||||
{installLink ? (
|
||||
<Link href={installLink} target="_blank" className="mb-12">
|
||||
{t("onboarding.extension.link")}
|
||||
</Link>
|
||||
) : null}
|
||||
|
||||
<ExtensionStatus status={value ?? "unknown"} loading={loading} />
|
||||
<PageContent loading={loading} status={value ?? "unknown"} />
|
||||
<div className="flex justify-between items-center mt-8">
|
||||
<Button onClick={() => navigate("/onboarding")} theme="secondary">
|
||||
{t("onboarding.extension.back")}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { detect } from "detect-browser";
|
||||
import fscreen from "fscreen";
|
||||
import Hls from "hls.js";
|
||||
|
||||
|
@ -52,3 +53,26 @@ export function canPlayHlsNatively(video: HTMLVideoElement): boolean {
|
|||
if (Hls.isSupported()) return false; // no need to play natively
|
||||
return !!video.canPlayType("application/vnd.apple.mpegurl");
|
||||
}
|
||||
|
||||
export type ExtensionDetectionResult =
|
||||
| "unknown" // unknown detection or weird browser
|
||||
| "firefox" // firefox extensions
|
||||
| "chrome" // chrome extension (could be chromium, but still works with chrome extensions)
|
||||
| "ios"; // ios, no extensions
|
||||
|
||||
export function detectExtensionInstall(): ExtensionDetectionResult {
|
||||
const res = detect();
|
||||
|
||||
// not a browser or failed to detect
|
||||
if (res?.type !== "browser") return "unknown";
|
||||
|
||||
if (res.name === "ios" || res.name === "ios-webview") return "ios";
|
||||
if (
|
||||
res.name === "chrome" ||
|
||||
res.name === "chromium-webview" ||
|
||||
res.name === "edge-chromium"
|
||||
)
|
||||
return "chrome";
|
||||
if (res.name === "firefox") return "firefox";
|
||||
return "unknown";
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue