diff --git a/src/setup/App.tsx b/src/setup/App.tsx
index 375f5d6d..03388d58 100644
--- a/src/setup/App.tsx
+++ b/src/setup/App.tsx
@@ -9,6 +9,8 @@ import { MWMediaType } from "@/backend/metadata/types";
import { V2MigrationView } from "@/views/other/v2Migration";
import { DeveloperView } from "@/views/developer/DeveloperView";
import { VideoTesterView } from "@/views/developer/VideoTesterView";
+import { ProviderTesterView } from "@/views/developer/ProviderTesterView";
+import { EmbedTesterView } from "@/views/developer/EmbedTesterView";
function App() {
return (
@@ -33,6 +35,8 @@ function App() {
{/* other */}
+
+
diff --git a/src/views/developer/DeveloperView.tsx b/src/views/developer/DeveloperView.tsx
index f2a9d30d..419293a5 100644
--- a/src/views/developer/DeveloperView.tsx
+++ b/src/views/developer/DeveloperView.tsx
@@ -14,6 +14,11 @@ export function DeveloperView() {
direction="right"
linkText="Provider tester"
/>
+
diff --git a/src/views/developer/EmbedTesterView.tsx b/src/views/developer/EmbedTesterView.tsx
new file mode 100644
index 00000000..dd4cef10
--- /dev/null
+++ b/src/views/developer/EmbedTesterView.tsx
@@ -0,0 +1,136 @@
+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";
+import { ReactNode, useCallback, useEffect, useMemo, useState } from "react";
+
+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 (
+
+
Input embed url
+
+ setUrl(e.target.value)}
+ />
+
+
+
+ );
+}
+
+function MediaScraper(props: MediaScraperProps) {
+ const [results, setResults] = useState(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 Scraping... ({percentage}%)
;
+ if (error) return Errored, check console
;
+
+ return (
+
+
Output data
+
+ {JSON.stringify(results, null, 2)}
+
+
+ );
+}
+
+function EmbedScraperSelector(props: EmbedScraperSelectorProps) {
+ const embedScrapers = getEmbeds();
+
+ return (
+
+
Choose embed scraper
+ {embedScrapers.map((v) => (
+
props.onSelect(v.id)}
+ direction="right"
+ linkText={v.displayName}
+ />
+ ))}
+
+ );
+}
+
+export function EmbedTesterView() {
+ const [embed, setEmbed] = useState(null);
+ const [embedScraperId, setEmbedScraperId] = useState(null);
+ const embedScraper = useMemo(
+ () => getEmbeds().find((v) => v.id === embedScraperId),
+ [embedScraperId]
+ );
+
+ let content: ReactNode = null;
+ if (!embedScraperId || !embedScraper) {
+ content = setEmbedScraperId(id)} />;
+ } else if (!embed) {
+ content = (
+ setEmbed(v)}
+ />
+ );
+ } else {
+ content = ;
+ }
+
+ return (
+
+ );
+}
diff --git a/src/views/developer/ProviderTesterView.tsx b/src/views/developer/ProviderTesterView.tsx
new file mode 100644
index 00000000..8cc4ed0a
--- /dev/null
+++ b/src/views/developer/ProviderTesterView.tsx
@@ -0,0 +1,159 @@
+import { MWProviderScrapeResult } from "@/backend/helpers/provider";
+import { getProviders } from "@/backend/helpers/register";
+import { runProvider } from "@/backend/helpers/run";
+import { DetailedMeta } from "@/backend/metadata/getmeta";
+import { MWMediaType } from "@/backend/metadata/types";
+import { Navigation } from "@/components/layout/Navigation";
+import { ArrowLink } from "@/components/text/ArrowLink";
+import { Title } from "@/components/text/Title";
+import { useLoading } from "@/hooks/useLoading";
+import { ReactNode, useEffect, useState } from "react";
+
+interface MediaSelectorProps {
+ onSelect: (meta: DetailedMeta) => void;
+}
+
+interface ProviderSelectorProps {
+ onSelect: (providerId: string) => void;
+}
+
+interface MediaScraperProps {
+ media: DetailedMeta | null;
+ id: string;
+}
+
+function MediaSelector(props: MediaSelectorProps) {
+ const options: DetailedMeta[] = [
+ {
+ imdbId: "tt10954562",
+ tmdbId: "572716",
+ meta: {
+ id: "439596",
+ title: "Hamilton",
+ type: MWMediaType.MOVIE,
+ year: "2020",
+ seasons: undefined,
+ },
+ },
+ {
+ imdbId: "tt11126994",
+ tmdbId: "94605",
+ meta: {
+ id: "222333",
+ title: "Arcane",
+ type: MWMediaType.SERIES,
+ year: "2021",
+ seasons: [
+ {
+ id: "230301",
+ number: 1,
+ title: "Season 1",
+ },
+ ],
+ seasonData: {
+ id: "230301",
+ number: 1,
+ title: "Season 1",
+ episodes: [
+ {
+ id: "4243445",
+ number: 1,
+ title: "Welcome to the Playground",
+ },
+ ],
+ },
+ },
+ },
+ ];
+
+ return (
+
+
Choose media
+ {options.map((v) => (
+
props.onSelect(v)}
+ direction="right"
+ linkText={`${v.meta.title} (${v.meta.type})`}
+ />
+ ))}
+
+ );
+}
+
+function MediaScraper(props: MediaScraperProps) {
+ const [results, setResults] = useState(null);
+ const [percentage, setPercentage] = useState(0);
+
+ const [scrape, loading, error] = useLoading(async (media: DetailedMeta) => {
+ const provider = getProviders().find((v) => v.id === props.id);
+ if (!provider) throw new Error("provider not found");
+ const data = await runProvider(provider, {
+ progress(num) {
+ console.log(`SCRAPING AT ${num}%`);
+ setPercentage(num);
+ },
+ media,
+ type: media.meta.type as any,
+ });
+ console.log("got data", data);
+ setResults(data);
+ });
+
+ useEffect(() => {
+ if (props.media) {
+ scrape(props.media);
+ }
+ }, [props.media, scrape]);
+
+ if (loading) return Scraping... ({percentage}%)
;
+ if (error) return Errored, check console
;
+
+ return (
+
+
Output data
+
+ {JSON.stringify(results, null, 2)}
+
+
+ );
+}
+
+function ProviderSelector(props: ProviderSelectorProps) {
+ const providers = getProviders();
+
+ return (
+
+
Choose provider
+ {providers.map((v) => (
+
props.onSelect(v.id)}
+ direction="right"
+ linkText={v.displayName}
+ />
+ ))}
+
+ );
+}
+
+export function ProviderTesterView() {
+ const [media, setMedia] = useState(null);
+ const [providerId, setProviderId] = useState(null);
+
+ let content: ReactNode = null;
+ if (!providerId) {
+ content = setProviderId(id)} />;
+ } else if (!media) {
+ content = setMedia(v)} />;
+ } else {
+ content = ;
+ }
+
+ return (
+
+ );
+}
diff --git a/src/views/developer/VideoTesterView.tsx b/src/views/developer/VideoTesterView.tsx
index 6bf34719..7681af6e 100644
--- a/src/views/developer/VideoTesterView.tsx
+++ b/src/views/developer/VideoTesterView.tsx
@@ -2,6 +2,7 @@ import { MWStreamQuality, MWStreamType } from "@/backend/helpers/streams";
import { DetailedMeta } from "@/backend/metadata/getmeta";
import { MWMediaType } from "@/backend/metadata/types";
import { Button } from "@/components/Button";
+import { Dropdown } from "@/components/Dropdown";
import { Navigation } from "@/components/layout/Navigation";
import { ThinContainer } from "@/components/layout/ThinContainer";
import { MetaController } from "@/video/components/controllers/MetaController";
@@ -12,11 +13,13 @@ import { Helmet } from "react-helmet";
interface VideoData {
streamUrl: string;
+ type: MWStreamType;
}
const testData: VideoData = {
streamUrl:
"http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4",
+ type: MWStreamType.MP4,
};
const testMeta: DetailedMeta = {
imdbId: "",
@@ -32,13 +35,18 @@ const testMeta: DetailedMeta = {
export function VideoTesterView() {
const [video, setVideo] = useState(null);
+ const [videoType, setVideoType] = useState(MWStreamType.MP4);
const [url, setUrl] = useState("");
- const playVideo = useCallback((streamUrl: string) => {
- setVideo({
- streamUrl,
- });
- }, []);
+ const playVideo = useCallback(
+ (streamUrl: string) => {
+ setVideo({
+ streamUrl,
+ type: videoType,
+ });
+ },
+ [videoType]
+ );
if (video) {
return (
@@ -65,18 +73,36 @@ export function VideoTesterView() {
}
return (
-