A small web app for watching movies and shows easily
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

137 lines
3.6 KiB

import { ReactNode, useCallback, useEffect, useMemo, useState } from "react";
import { MWEmbed, MWEmbedScraper, MWEmbedType } from "@/backend/helpers/embed";
import { getEmbeds } from "@/backend/helpers/register";
import { runEmbedScraper } from "@/backend/helpers/run";
import { MWStream } from "@/backend/helpers/streams";
import { Button } from "@/components/Button";
import { Navigation } from "@/components/layout/Navigation";
import { ArrowLink } from "@/components/text/ArrowLink";
import { Title } from "@/components/text/Title";
import { useLoading } from "@/hooks/useLoading";
interface MediaSelectorProps {
embedType: MWEmbedType;
onSelect: (meta: MWEmbed) => void;
}
interface EmbedScraperSelectorProps {
onSelect: (embedScraperId: string) => void;
}
interface MediaScraperProps {
embed: MWEmbed;
scraper: MWEmbedScraper;
}
function MediaSelector(props: MediaSelectorProps) {
const [url, setUrl] = useState("");
const select = useCallback(
(urlSt: string) => {
props.onSelect({
type: props.embedType,
url: urlSt,
});
},
[props]
);
return (
<div className="flex flex-col space-y-4">
<Title className="mb-8">Input embed url</Title>
<div className="mb-4 flex gap-4">
<input
type="text"
placeholder="embed url here..."
value={url}
onChange={(e) => setUrl(e.target.value)}
/>
<Button onClick={() => select(url)}>Run scraper</Button>
</div>
</div>
);
}
function MediaScraper(props: MediaScraperProps) {
const [results, setResults] = useState<MWStream | null>(null);
const [percentage, setPercentage] = useState(0);
const [scrape, loading, error] = useLoading(async (url: string) => {
const data = await runEmbedScraper(props.scraper, {
url,
progress(num) {
console.log(`SCRAPING AT ${num}%`);
setPercentage(num);
},
});
console.log("got data", data);
setResults(data);
});
useEffect(() => {
if (props.embed) {
scrape(props.embed.url);
}
}, [props.embed, scrape]);
if (loading) return <p>Scraping... ({percentage}%)</p>;
if (error) return <p>Errored, check console</p>;
return (
<div>
<Title className="mb-8">Output data</Title>
<code>
<pre>{JSON.stringify(results, null, 2)}</pre>
</code>
</div>
);
}
function EmbedScraperSelector(props: EmbedScraperSelectorProps) {
const embedScrapers = getEmbeds();
return (
<div className="flex flex-col space-y-4">
<Title className="mb-8">Choose embed scraper</Title>
{embedScrapers.map((v) => (
<ArrowLink
key={v.id}
onClick={() => props.onSelect(v.id)}
direction="right"
linkText={v.displayName}
/>
))}
</div>
);
}
export default function EmbedTesterView() {
const [embed, setEmbed] = useState<MWEmbed | null>(null);
const [embedScraperId, setEmbedScraperId] = useState<string | null>(null);
const embedScraper = useMemo(
() => getEmbeds().find((v) => v.id === embedScraperId),
[embedScraperId]
);
let content: ReactNode = null;
if (!embedScraperId || !embedScraper) {
content = <EmbedScraperSelector onSelect={(id) => setEmbedScraperId(id)} />;
} else if (!embed) {
content = (
<MediaSelector
embedType={embedScraper.for}
onSelect={(v) => setEmbed(v)}
/>
);
} else {
content = <MediaScraper scraper={embedScraper} embed={embed} />;
}
return (
<div className="py-48">
<Navigation />
<div className="mx-8 overflow-x-auto">{content}</div>
</div>
);
}