mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-02-15 04:32:13 +00:00
feat: Add SeedersAndPeers component with skeleton loader
This commit is contained in:
parent
1872ff1d24
commit
58693fdb00
4 changed files with 154 additions and 0 deletions
|
@ -0,0 +1,20 @@
|
||||||
|
import Skeleton from "react-loading-skeleton";
|
||||||
|
|
||||||
|
export function SeedersAndPeersSkeleton() {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Skeleton width={40} height={20} />
|
||||||
|
<Skeleton
|
||||||
|
width={40}
|
||||||
|
height={20}
|
||||||
|
style={{
|
||||||
|
marginLeft: "12px",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
import { GameRepack } from "@types";
|
||||||
|
import { Sprout, Users } from "lucide-react";
|
||||||
|
|
||||||
|
import { useMagnetData } from "./useMagnetData";
|
||||||
|
import { Tooltip } from "@renderer/components/tooltip/tooltip";
|
||||||
|
import { SeedersAndPeersSkeleton } from "./seeders-and-peers-skeleton";
|
||||||
|
import { vars } from "@renderer/theme.css";
|
||||||
|
|
||||||
|
interface SeedersAndPeersProps {
|
||||||
|
repack: GameRepack;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SeedersAndPeers({ repack }: Readonly<SeedersAndPeersProps>) {
|
||||||
|
const { magnetData, isLoading, error } = useMagnetData(repack.magnet);
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return <SeedersAndPeersSkeleton />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-around",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Tooltip tooltipText="Seeders">
|
||||||
|
<Sprout size={16} stroke={vars.color.bodyText} />
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
marginLeft: "7px",
|
||||||
|
marginRight: "8px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{magnetData?.seeders}
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip tooltipText="Peers">
|
||||||
|
<Users size={16} stroke={vars.color.bodyText} />
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
marginLeft: "7px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{magnetData?.peers}
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
export type TorrentData = {
|
||||||
|
seeders: number;
|
||||||
|
peers: number;
|
||||||
|
lastTracked?: Date;
|
||||||
|
};
|
|
@ -0,0 +1,75 @@
|
||||||
|
import { useCallback, useEffect, useState } from "react";
|
||||||
|
import { TorrentData } from "./types";
|
||||||
|
|
||||||
|
const cache: Record<string, TorrentData> = {};
|
||||||
|
|
||||||
|
export function useMagnetData(magnet: string) {
|
||||||
|
const [magnetData, setMagnetData] = useState<TorrentData | null>(cache[magnet] || null);
|
||||||
|
const [isLoading, setIsLoading] = useState(() => {
|
||||||
|
if (cache[magnet]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
const [error, setError] = useState<Error | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!magnet) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cache[magnet]) {
|
||||||
|
setMagnetData(cache[magnet]);
|
||||||
|
setIsLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.electron.getMagnetData(magnet).then(
|
||||||
|
(result) => {
|
||||||
|
if (result) {
|
||||||
|
setMagnetData(result);
|
||||||
|
setIsLoading(false);
|
||||||
|
|
||||||
|
cache[magnet] = result;
|
||||||
|
cache[magnet].lastTracked = new Date();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
setError(error);
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const invalidateCache = useCallback(() => {
|
||||||
|
const TWO_MINUTES = 2 * 60 * 1000;
|
||||||
|
const cacheExpiresIn = TWO_MINUTES;
|
||||||
|
|
||||||
|
Object.keys(cache).forEach((key) => {
|
||||||
|
const lastTracked = cache[key].lastTracked;
|
||||||
|
|
||||||
|
if (!lastTracked) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Date.now() - lastTracked.getTime() > cacheExpiresIn) {
|
||||||
|
delete cache[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
invalidateCache();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
invalidateCache();
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return {
|
||||||
|
magnetData,
|
||||||
|
isLoading,
|
||||||
|
error,
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in a new issue