mirror of
https://github.com/oiov/wr.do.git
synced 2026-05-06 13:40:12 +08:00
590 lines
18 KiB
TypeScript
590 lines
18 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import JsonView from "@uiw/react-json-view";
|
|
import { githubLightTheme } from "@uiw/react-json-view/githubLight";
|
|
import { vscodeTheme } from "@uiw/react-json-view/vscode";
|
|
import { useTranslations } from "next-intl";
|
|
import { useTheme } from "next-themes";
|
|
import { toast } from "sonner";
|
|
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
Card,
|
|
CardContent,
|
|
CardDescription,
|
|
CardHeader,
|
|
CardTitle,
|
|
} from "@/components/ui/card";
|
|
import { Input } from "@/components/ui/input";
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from "@/components/ui/select";
|
|
import BlurImage from "@/components/shared/blur-image";
|
|
|
|
export interface MetaScrapingProps {
|
|
title: string;
|
|
description: string;
|
|
image: string;
|
|
icon: string;
|
|
url: string;
|
|
lang: string;
|
|
author: string;
|
|
timestamp: string;
|
|
payload: string;
|
|
}
|
|
|
|
export interface MarkdownScrapingProps {
|
|
url: string;
|
|
content: string;
|
|
format: string;
|
|
timestamp: string;
|
|
payload: string;
|
|
}
|
|
|
|
export function ScreenshotScraping({
|
|
user,
|
|
}: {
|
|
user: { id: string; apiKey: string };
|
|
}) {
|
|
const t = useTranslations("Scrape");
|
|
const { theme } = useTheme();
|
|
const [protocol, setProtocol] = useState("https://");
|
|
|
|
const [isShoting, setIsShoting] = useState(false);
|
|
const [currentScreenshotLink, setCurrentScreenshotLink] =
|
|
useState("vmail.dev");
|
|
const [screenshotInfo, setScreenshotInfo] = useState({
|
|
tmp_url: "",
|
|
payload: "",
|
|
});
|
|
|
|
const handleScrapingScreenshot = async () => {
|
|
if (currentScreenshotLink) {
|
|
setIsShoting(true);
|
|
const payload = `/api/v1/scraping/screenshot?url=${protocol}${currentScreenshotLink}&key=${user.apiKey}`;
|
|
const res = await fetch(payload);
|
|
if (!res.ok || res.status !== 200) {
|
|
const data = await res.json();
|
|
toast.error(data.statusText);
|
|
} else {
|
|
const blob = await res.blob();
|
|
const imageUrl = URL.createObjectURL(blob);
|
|
setScreenshotInfo({
|
|
tmp_url: imageUrl,
|
|
payload: `${window.location.origin}${payload}`,
|
|
});
|
|
toast.success("Success!");
|
|
}
|
|
setIsShoting(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<CodeLight content={`https://wr.do/api/v1/scraping/screenshot`} />
|
|
<Card className="bg-gray-50 dark:bg-gray-900">
|
|
<CardHeader>
|
|
<CardTitle>{t("Playground")}</CardTitle>
|
|
<CardDescription>
|
|
{t(
|
|
"Automate your website screenshots and turn them into stunning visuals for your applications",
|
|
)}
|
|
.
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="flex items-center">
|
|
<Select
|
|
onValueChange={(value: string) => {
|
|
setProtocol(value);
|
|
}}
|
|
name="protocol"
|
|
defaultValue="https://"
|
|
>
|
|
<SelectTrigger className="h-10 w-24 rounded-r-none bg-transparent shadow-inner">
|
|
<SelectValue placeholder="Protocol" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem key="https" value="https://">
|
|
https://
|
|
</SelectItem>
|
|
<SelectItem key="http" value="http://">
|
|
http://
|
|
</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
<Input
|
|
type="text"
|
|
placeholder="www.example.com"
|
|
className="h-10 rounded-none border focus:border-primary active:border-primary"
|
|
value={currentScreenshotLink}
|
|
size={100}
|
|
onChange={(e) => setCurrentScreenshotLink(e.target.value)}
|
|
/>
|
|
<Button
|
|
variant="blue"
|
|
onClick={handleScrapingScreenshot}
|
|
disabled={isShoting}
|
|
className="w-28 rounded-l-none"
|
|
>
|
|
{isShoting ? t("Scraping") : t("Start")}
|
|
</Button>
|
|
</div>
|
|
|
|
<div className="mt-4 rounded-md border p-3">
|
|
<JsonView
|
|
className="max-w-2xl overflow-auto p-2"
|
|
style={theme === "dark" ? vscodeTheme : githubLightTheme}
|
|
value={screenshotInfo}
|
|
displayObjectSize={false}
|
|
displayDataTypes={false}
|
|
// shortenTextAfterLength={50}
|
|
/>
|
|
{screenshotInfo.tmp_url && (
|
|
<BlurImage
|
|
src={screenshotInfo.tmp_url}
|
|
alt="ligth preview landing"
|
|
className="my-4 flex rounded-md border object-contain object-center shadow-md"
|
|
width={1500}
|
|
height={750}
|
|
priority
|
|
// placeholder="blur"
|
|
/>
|
|
)}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</>
|
|
);
|
|
}
|
|
|
|
export function MetaScraping({
|
|
user,
|
|
}: {
|
|
user: { id: string; apiKey: string };
|
|
}) {
|
|
const t = useTranslations("Scrape");
|
|
const { theme } = useTheme();
|
|
const [currentLink, setCurrentLink] = useState("wr.do");
|
|
const [protocol, setProtocol] = useState("https://");
|
|
const [metaInfo, setMetaInfo] = useState<MetaScrapingProps>({
|
|
title: "",
|
|
description: "",
|
|
image: "",
|
|
icon: "",
|
|
url: "",
|
|
lang: "",
|
|
author: "",
|
|
timestamp: "",
|
|
payload: "",
|
|
});
|
|
const [isScraping, setIsScraping] = useState(false);
|
|
|
|
const handleScrapingMeta = async () => {
|
|
if (currentLink) {
|
|
setIsScraping(true);
|
|
const res = await fetch(
|
|
`/api/v1/scraping/meta?url=${protocol}${currentLink}&key=${user.apiKey}`,
|
|
);
|
|
if (!res.ok || res.status !== 200) {
|
|
const data = await res.json();
|
|
toast.error(data.statusText);
|
|
} else {
|
|
const data = await res.json();
|
|
setMetaInfo(data);
|
|
toast.success("Success!");
|
|
}
|
|
setIsScraping(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<CodeLight content={`https://wr.do/api/v1/scraping/meta`} />
|
|
<Card className="bg-gray-50 dark:bg-gray-900">
|
|
<CardHeader>
|
|
<CardTitle>{t("Playground")}</CardTitle>
|
|
<CardDescription>
|
|
{t("Scrape the meta data of a website")}.
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="flex items-center">
|
|
<Select
|
|
onValueChange={(value: string) => {
|
|
setProtocol(value);
|
|
}}
|
|
name="protocol"
|
|
defaultValue={"https://"}
|
|
>
|
|
<SelectTrigger className="h-10 w-24 rounded-r-none bg-transparent shadow-inner">
|
|
<SelectValue placeholder="Protocol" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem key="https" value="https://">
|
|
https://
|
|
</SelectItem>
|
|
<SelectItem key="http" value="http://">
|
|
http://
|
|
</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
<Input
|
|
type="text"
|
|
placeholder="www.example.com"
|
|
className="h-10 rounded-none border focus:border-primary active:border-primary"
|
|
value={currentLink}
|
|
size={100}
|
|
onChange={(e) => setCurrentLink(e.target.value)}
|
|
/>
|
|
<Button
|
|
variant="blue"
|
|
onClick={handleScrapingMeta}
|
|
disabled={isScraping}
|
|
className="w-28 rounded-l-none"
|
|
>
|
|
{isScraping ? t("Scraping") : t("Start")}
|
|
</Button>
|
|
</div>
|
|
|
|
<div className="mt-4 rounded-md border p-3">
|
|
<JsonView
|
|
style={theme === "dark" ? vscodeTheme : githubLightTheme}
|
|
value={metaInfo}
|
|
displayObjectSize={false}
|
|
displayDataTypes={false}
|
|
/>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</>
|
|
);
|
|
}
|
|
|
|
export function MarkdownScraping({
|
|
user,
|
|
}: {
|
|
user: { id: string; apiKey: string };
|
|
}) {
|
|
const t = useTranslations("Scrape");
|
|
const { theme } = useTheme();
|
|
const [currentLink, setCurrentLink] = useState("wr.do");
|
|
const [protocol, setProtocol] = useState("https://");
|
|
const [metaInfo, setMetaInfo] = useState<MarkdownScrapingProps>({
|
|
url: "",
|
|
content: "",
|
|
format: "",
|
|
timestamp: "",
|
|
payload: "",
|
|
});
|
|
const [isScraping, setIsScraping] = useState(false);
|
|
|
|
const handleScrapingMeta = async () => {
|
|
if (currentLink) {
|
|
setIsScraping(true);
|
|
const res = await fetch(
|
|
`/api/v1/scraping/markdown?url=${protocol}${currentLink}&key=${user.apiKey}`,
|
|
);
|
|
if (!res.ok || res.status !== 200) {
|
|
const data = await res.json();
|
|
toast.error(data.statusText);
|
|
} else {
|
|
const data = await res.json();
|
|
setMetaInfo(data);
|
|
toast.success("Success!");
|
|
}
|
|
setIsScraping(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<CodeLight content={`https://wr.do/api/v1/scraping/markdown`} />
|
|
<Card className="bg-gray-50 dark:bg-gray-900">
|
|
<CardHeader>
|
|
<CardTitle>Markdown</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="flex items-center">
|
|
<Select
|
|
onValueChange={(value: string) => {
|
|
setProtocol(value);
|
|
}}
|
|
name="protocol"
|
|
defaultValue={"https://"}
|
|
>
|
|
<SelectTrigger className="h-10 w-24 rounded-r-none bg-transparent shadow-inner">
|
|
<SelectValue placeholder="Protocol" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem key="https" value="https://">
|
|
https://
|
|
</SelectItem>
|
|
<SelectItem key="http" value="http://">
|
|
http://
|
|
</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
<Input
|
|
type="text"
|
|
placeholder="www.example.com"
|
|
className="h-10 rounded-none border focus:border-primary active:border-primary"
|
|
value={currentLink}
|
|
size={100}
|
|
onChange={(e) => setCurrentLink(e.target.value)}
|
|
/>
|
|
<Button
|
|
variant="blue"
|
|
onClick={handleScrapingMeta}
|
|
disabled={isScraping}
|
|
className="w-28 rounded-l-none"
|
|
>
|
|
{isScraping ? t("Scraping") : t("Start")}
|
|
</Button>
|
|
</div>
|
|
|
|
<div className="mt-4 rounded-md border p-3">
|
|
<JsonView
|
|
style={theme === "dark" ? vscodeTheme : githubLightTheme}
|
|
value={metaInfo}
|
|
displayObjectSize={false}
|
|
displayDataTypes={false}
|
|
/>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</>
|
|
);
|
|
}
|
|
|
|
export function TextScraping({
|
|
user,
|
|
}: {
|
|
user: { id: string; apiKey: string };
|
|
}) {
|
|
const t = useTranslations("Scrape");
|
|
const { theme } = useTheme();
|
|
const [currentLink, setCurrentLink] = useState("wr.do");
|
|
const [protocol, setProtocol] = useState("https://");
|
|
const [metaInfo, setMetaInfo] = useState<MarkdownScrapingProps>({
|
|
url: "",
|
|
content: "",
|
|
format: "",
|
|
timestamp: "",
|
|
payload: "",
|
|
});
|
|
const [isScraping, setIsScraping] = useState(false);
|
|
|
|
const handleScrapingMeta = async () => {
|
|
if (currentLink) {
|
|
setIsScraping(true);
|
|
const res = await fetch(
|
|
`/api/v1/scraping/text?url=${protocol}${currentLink}&key=${user.apiKey}`,
|
|
);
|
|
if (!res.ok || res.status !== 200) {
|
|
const data = await res.json();
|
|
toast.error(data.statusText);
|
|
} else {
|
|
const data = await res.json();
|
|
setMetaInfo(data);
|
|
toast.success("Success!");
|
|
}
|
|
setIsScraping(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<CodeLight content={`https://wr.do/api/v1/scraping/text`} />
|
|
<Card className="bg-gray-50 dark:bg-gray-900">
|
|
<CardHeader>
|
|
<CardTitle>{t("Text")}</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="flex items-center">
|
|
<Select
|
|
onValueChange={(value: string) => {
|
|
setProtocol(value);
|
|
}}
|
|
name="protocol"
|
|
defaultValue={"https://"}
|
|
>
|
|
<SelectTrigger className="h-10 w-24 rounded-r-none bg-transparent shadow-inner">
|
|
<SelectValue placeholder="Protocol" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem key="https" value="https://">
|
|
https://
|
|
</SelectItem>
|
|
<SelectItem key="http" value="http://">
|
|
http://
|
|
</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
<Input
|
|
type="text"
|
|
placeholder="www.example.com"
|
|
className="h-10 rounded-none border focus:border-primary active:border-primary"
|
|
value={currentLink}
|
|
size={100}
|
|
onChange={(e) => setCurrentLink(e.target.value)}
|
|
/>
|
|
<Button
|
|
variant="blue"
|
|
onClick={handleScrapingMeta}
|
|
disabled={isScraping}
|
|
className="w-28 rounded-l-none"
|
|
>
|
|
{isScraping ? t("Scraping") : t("Start")}
|
|
</Button>
|
|
</div>
|
|
|
|
<div className="mt-4 rounded-md border p-3">
|
|
<JsonView
|
|
style={theme === "dark" ? vscodeTheme : githubLightTheme}
|
|
value={metaInfo}
|
|
displayObjectSize={false}
|
|
displayDataTypes={false}
|
|
/>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</>
|
|
);
|
|
}
|
|
|
|
export function QrCodeScraping({
|
|
user,
|
|
}: {
|
|
user: { id: string; apiKey: string };
|
|
}) {
|
|
const t = useTranslations("Scrape");
|
|
const { theme } = useTheme();
|
|
const [protocol, setProtocol] = useState("https://");
|
|
|
|
const [isShoting, setIsShoting] = useState(false);
|
|
const [currentScreenshotLink, setCurrentScreenshotLink] =
|
|
useState("vmail.dev");
|
|
const [qrInfo, setQrInfo] = useState({
|
|
// tmp_url: "",
|
|
payload: "",
|
|
});
|
|
|
|
const handleScrapingScreenshot = async () => {
|
|
if (currentScreenshotLink) {
|
|
setIsShoting(true);
|
|
const payload = `/api/v1/scraping/qrcode?url=${protocol}${currentScreenshotLink}&key=${user.apiKey}`;
|
|
const res = await fetch(payload);
|
|
if (!res.ok || res.status !== 200) {
|
|
toast.error(res.statusText);
|
|
} else {
|
|
setQrInfo({
|
|
payload: `${window.location.origin}${payload}`,
|
|
});
|
|
toast.success("Success!");
|
|
}
|
|
setIsShoting(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<CodeLight content={`https://wr.do/api/v1/scraping/qrcode`} />
|
|
<Card className="bg-gray-50 dark:bg-gray-900">
|
|
<CardHeader>
|
|
<CardTitle>{t("Playground")}</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="flex items-center">
|
|
<Select
|
|
onValueChange={(value: string) => {
|
|
setProtocol(value);
|
|
}}
|
|
name="protocol"
|
|
defaultValue="https://"
|
|
>
|
|
<SelectTrigger className="h-10 w-24 rounded-r-none bg-transparent shadow-inner">
|
|
<SelectValue placeholder="Protocol" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem key="https" value="https://">
|
|
https://
|
|
</SelectItem>
|
|
<SelectItem key="http" value="http://">
|
|
http://
|
|
</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
<Input
|
|
type="text"
|
|
placeholder="www.example.com"
|
|
className="h-10 rounded-none border focus:border-primary active:border-primary"
|
|
value={currentScreenshotLink}
|
|
size={100}
|
|
onChange={(e) => setCurrentScreenshotLink(e.target.value)}
|
|
/>
|
|
<Button
|
|
variant="blue"
|
|
onClick={handleScrapingScreenshot}
|
|
disabled={isShoting}
|
|
className="rounded-l-none"
|
|
>
|
|
{isShoting ? "Scraping..." : "Send"}
|
|
</Button>
|
|
</div>
|
|
|
|
<div className="mt-4 rounded-md border p-3">
|
|
<JsonView
|
|
className="max-w-2xl overflow-auto p-2"
|
|
style={theme === "dark" ? vscodeTheme : githubLightTheme}
|
|
value={qrInfo}
|
|
displayObjectSize={false}
|
|
displayDataTypes={false}
|
|
// shortenTextAfterLength={50}
|
|
/>
|
|
{qrInfo.payload && (
|
|
<BlurImage
|
|
src={qrInfo.payload}
|
|
alt="ligth preview landing"
|
|
className="my-4 flex rounded-md border object-contain object-center shadow-md"
|
|
width={150}
|
|
height={150}
|
|
priority
|
|
// placeholder="blur"
|
|
/>
|
|
)}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</>
|
|
);
|
|
}
|
|
|
|
export const CodeLight = ({ content }: { content: string }) => {
|
|
const code = content.trim();
|
|
|
|
return (
|
|
<div className="mx-auto w-full">
|
|
<pre className="overflow-x-auto rounded-lg bg-gray-900 p-4 text-gray-100">
|
|
<code className="block font-mono text-sm">
|
|
{code.split("\n").map((line, i) => (
|
|
<div key={i} className="group relative">
|
|
{/* Line number */}
|
|
<span className="inline-block w-8 select-none text-gray-500">
|
|
{i + 1}
|
|
</span>
|
|
{/* Code content */}
|
|
<span className="text-blue-400">{line}</span>
|
|
</div>
|
|
))}
|
|
</code>
|
|
</pre>
|
|
</div>
|
|
);
|
|
};
|