Improve link previewer cpn

This commit is contained in:
oiov
2025-08-06 10:56:30 +08:00
parent bc20bb2fec
commit d47689adcf
9 changed files with 83 additions and 19 deletions

View File

@@ -6,7 +6,7 @@ import { ScrapeMeta } from "@prisma/client";
import { useTranslations } from "next-intl";
import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from "recharts";
import { isLink, nFormatter, removeUrlSuffix } from "@/lib/utils";
import { isLink, nFormatter, removeUrlPrefix } from "@/lib/utils";
import {
Card,
CardContent,
@@ -268,7 +268,7 @@ export function StatsList({ data, title }: { data: Stat[]; title: string }) {
className="truncate font-medium hover:opacity-70 hover:after:content-['↗']"
href={ref.dimension}
>
{removeUrlSuffix(ref.dimension)}
{removeUrlPrefix(ref.dimension)}
</Link>
) : (
<p className="font-medium">{decodeURIComponent(ref.dimension)}</p>

View File

@@ -20,7 +20,7 @@ import {
getRegionName,
} from "@/lib/contries";
import { DATE_DIMENSION_ENUMS } from "@/lib/enums";
import { fetcher, isLink, removeUrlSuffix } from "@/lib/utils";
import { fetcher, isLink, removeUrlPrefix } from "@/lib/utils";
import { useElementSize } from "@/hooks/use-element-size";
import { Button } from "@/components/ui/button";
import {
@@ -532,7 +532,7 @@ export function StatsList({ data, title }: { data: Stat[]; title: string }) {
href={ref.dimension}
target="_blank"
>
{removeUrlSuffix(ref.dimension)}
{removeUrlPrefix(ref.dimension)}
</Link>
) : (
<p className="font-medium">

View File

@@ -11,12 +11,13 @@ import useSWR, { useSWRConfig } from "swr";
import { ShortUrlFormData } from "@/lib/dto/short-urls";
import {
addUrlPrefix,
cn,
expirationTime,
extractHostname,
fetcher,
nFormatter,
removeUrlSuffix,
removeUrlPrefix,
} from "@/lib/utils";
import { useMediaQuery } from "@/hooks/use-media-query";
import { Button } from "@/components/ui/button";
@@ -365,8 +366,8 @@ export default function UserUrlsList({ user, action }: UrlListProps) {
<TableCell className="col-span-1 flex items-center justify-start sm:col-span-2">
<LinkInfoPreviewer
apiKey={user.apiKey ?? ""}
url={short.target}
formatUrl={removeUrlSuffix(short.target)}
url={addUrlPrefix(short.target)}
formatUrl={removeUrlPrefix(short.target)}
/>
</TableCell>
<TableCell className="col-span-1 hidden truncate sm:flex">
@@ -530,7 +531,7 @@ export default function UserUrlsList({ user, action }: UrlListProps) {
<LinkInfoPreviewer
apiKey={user.apiKey ?? ""}
url={short.target}
formatUrl={removeUrlSuffix(short.target)}
formatUrl={removeUrlPrefix(short.target)}
/>
</div>
</div>

View File

@@ -7,7 +7,7 @@ import { ChevronLeft, ChevronRight } from "lucide-react";
import { useTranslations } from "next-intl";
import { toast } from "sonner";
import { cn, removeUrlSuffix } from "@/lib/utils";
import { cn, removeUrlPrefix } from "@/lib/utils";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
@@ -272,7 +272,7 @@ function AddDomain({ onNextStep }: { onNextStep: () => void }) {
method: "POST",
body: JSON.stringify({
data: {
domain_name: removeUrlSuffix(domain),
domain_name: removeUrlPrefix(domain),
enable_short_link: true,
enable_email: true,
enable_dns: true,

View File

@@ -3,7 +3,7 @@ import cheerio from "cheerio";
import { checkApiKey } from "@/lib/dto/api-key";
import { createScrapeMeta } from "@/lib/dto/scrape";
import { getIpInfo } from "@/lib/geo";
import { isLink, removeUrlSuffix } from "@/lib/utils";
import { isLink, removeUrlPrefix } from "@/lib/utils";
export const revalidate = 600;
export const dynamic = "force-dynamic";
@@ -75,7 +75,7 @@ export async function GET(req: Request) {
const icon =
$("link[rel='icon']").attr("href") ||
$("link[rel='apple-touch-icon']").attr("href") ||
`https://icon.wr.do/${removeUrlSuffix(link)}.ico`;
`https://icon.wr.do/${removeUrlPrefix(link)}.ico`;
const lang =
$("html").attr("lang") ||
$("html").attr("xml:lang") ||

View File

@@ -33,7 +33,7 @@ export function BlurImg(props) {
className={cn(
props.className,
"duration-500 ease-in-out",
isLoading ? "animate-pulse blur-md" : "blur-0",
isLoading ? "blur-md" : "blur-0",
)}
onLoad={() => setLoading(false)}
/>

View File

@@ -11,7 +11,7 @@ import {
TooltipProvider,
TooltipTrigger,
} from "../ui/tooltip";
import BlurImage from "./blur-image";
import BlurImage, { BlurImg } from "./blur-image";
import { Icons } from "./icons";
export function LinkPreviewer({
@@ -112,8 +112,55 @@ export function LinkInfoPreviewer({
payload: "",
});
const isImageUrl = (url: string): boolean => {
const imageExtensions = [
".jpg",
".jpeg",
".png",
".gif",
".webp",
".svg",
".bmp",
".ico",
];
const urlLower = url.toLowerCase();
const hasImageExtension = imageExtensions.some((ext) =>
urlLower.includes(ext),
);
const imagePatterns = [
/\.(jpg|jpeg|png|gif|webp|svg|bmp|ico)(\?|#|$)/i,
/\/image\//i,
/\/img\//i,
/\/photos?\//i,
/\/pictures?\//i,
];
const matchesPattern = imagePatterns.some((pattern) => pattern.test(url));
return hasImageExtension || matchesPattern;
};
const handleScrapingInfo = async () => {
if (url) {
if (!url) return;
if (isImageUrl(url)) {
setMetaInfo({
title: formatUrl || url,
description: "",
image: url,
icon: "",
url: url,
lang: "",
author: "",
timestamp: "",
payload: "",
});
return;
}
try {
const res = await fetch(`/api/v1/scraping/meta?url=${url}&key=${apiKey}`);
if (!res.ok || res.status !== 200) {
setMetaInfo({
@@ -131,6 +178,19 @@ export function LinkInfoPreviewer({
const data = await res.json();
setMetaInfo({ ...data, title: data.title || url });
}
} catch (error) {
console.error("Error fetching meta info:", error);
setMetaInfo({
title: url,
description: "",
image: placeholdImage,
icon: "",
url: "",
lang: "",
author: "",
timestamp: "",
payload: "",
});
}
};
@@ -161,11 +221,11 @@ export function LinkInfoPreviewer({
<TooltipArrow className="fill-gray-400" />
{metaInfo.title ? (
<>
<BlurImage
<BlurImg
className="rounded-md bg-primary-foreground group-hover:scale-95 group-hover:opacity-95"
src={metaInfo.image || placeholdImage}
alt={`Preview of ${url}`}
fill
fit
/>
<div className="absolute bottom-0 w-full rounded-b-md p-2 backdrop-blur">
<p className="line-clamp-1 text-sm font-semibold text-neutral-600 dark:text-neutral-300">

View File

@@ -290,9 +290,12 @@ export function isLink(str: string): boolean {
}
}
export function removeUrlSuffix(url: string): string {
export function removeUrlPrefix(url: string): string {
return url.startsWith("http") ? url.split("//")[1] : url;
}
export function addUrlPrefix(url: string): string {
return url.startsWith("http") ? url : `https://${url}`;
}
export function extractHostname(url: string): string {
try {

File diff suppressed because one or more lines are too long