loading screen usescrape

This commit is contained in:
Jelle van Snik 2023-01-14 01:37:47 +01:00
parent cf83df64bb
commit 2f1058cb9c
7 changed files with 119 additions and 28 deletions

View File

@ -37,12 +37,14 @@ registerProvider({
rank: 69,
type: [MWMediaType.MOVIE],
async scrape({ media: { imdbId } }) {
async scrape({ progress, media: { imdbId } }) {
progress(10);
const streamRes = await fetch(
`${
conf().CORS_PROXY_URL
}https://database.gdriveplayer.us/player.php?imdb=${imdbId}`
).then((d) => d.text());
progress(90);
const page = new DOMParser().parseFromString(streamRes, "text/html");
const script: HTMLElement | undefined = Array.from(

View File

@ -22,6 +22,7 @@ export enum Icons {
COMPRESS = "compress",
VOLUME = "volume",
VOLUME_X = "volume_x",
X = "x",
}
export interface IconProps {
@ -51,6 +52,7 @@ const iconList: Record<Icons, string> = {
compress: `<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path fill="currentColor" d="M160 64c0-17.7-14.3-32-32-32s-32 14.3-32 32v64H32c-17.7 0-32 14.3-32 32s14.3 32 32 32h96c17.7 0 32-14.3 32-32V64zM32 320c-17.7 0-32 14.3-32 32s14.3 32 32 32H96v64c0 17.7 14.3 32 32 32s32-14.3 32-32V352c0-17.7-14.3-32-32-32H32zM352 64c0-17.7-14.3-32-32-32s-32 14.3-32 32v96c0 17.7 14.3 32 32 32h96c17.7 0 32-14.3 32-32s-14.3-32-32-32H352V64zM320 320c-17.7 0-32 14.3-32 32v96c0 17.7 14.3 32 32 32s32-14.3 32-32V384h64c17.7 0 32-14.3 32-32s-14.3-32-32-32H320z"/></svg>`,
volume: `<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 640 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path fill="currentColor" d="M533.6 32.5C598.5 85.3 640 165.8 640 256s-41.5 170.8-106.4 223.5c-10.3 8.4-25.4 6.8-33.8-3.5s-6.8-25.4 3.5-33.8C557.5 398.2 592 331.2 592 256s-34.5-142.2-88.7-186.3c-10.3-8.4-11.8-23.5-3.5-33.8s23.5-11.8 33.8-3.5zM473.1 107c43.2 35.2 70.9 88.9 70.9 149s-27.7 113.8-70.9 149c-10.3 8.4-25.4 6.8-33.8-3.5s-6.8-25.4 3.5-33.8C475.3 341.3 496 301.1 496 256s-20.7-85.3-53.2-111.8c-10.3-8.4-11.8-23.5-3.5-33.8s23.5-11.8 33.8-3.5zm-60.5 74.5C434.1 199.1 448 225.9 448 256s-13.9 56.9-35.4 74.5c-10.3 8.4-25.4 6.8-33.8-3.5s-6.8-25.4 3.5-33.8C393.1 284.4 400 271 400 256s-6.9-28.4-17.7-37.3c-10.3-8.4-11.8-23.5-3.5-33.8s23.5-11.8 33.8-3.5zM301.1 34.8C312.6 40 320 51.4 320 64V448c0 12.6-7.4 24-18.9 29.2s-25 3.1-34.4-5.3L131.8 352H64c-35.3 0-64-28.7-64-64V224c0-35.3 28.7-64 64-64h67.8L266.7 40.1c9.4-8.4 22.9-10.4 34.4-5.3z"/></svg>`,
volume_x: `<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 576 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path fill="currentColor" d="M301.1 34.8C312.6 40 320 51.4 320 64V448c0 12.6-7.4 24-18.9 29.2s-25 3.1-34.4-5.3L131.8 352H64c-35.3 0-64-28.7-64-64V224c0-35.3 28.7-64 64-64h67.8L266.7 40.1c9.4-8.4 22.9-10.4 34.4-5.3zM425 167l55 55 55-55c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9l-55 55 55 55c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0l-55-55-55 55c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l55-55-55-55c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0z"/></svg>`,
x: `<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 320 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path fill="currentColor" d="M310.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L160 210.7 54.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L114.7 256 9.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 301.3 265.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L205.3 256 310.6 150.6z"/></svg>`,
};
export const Icon = memo((props: IconProps) => {

View File

@ -1,6 +1,7 @@
import { Link } from "react-router-dom";
import { DotList } from "@/components/text/DotList";
import { MWMediaMeta } from "@/backend/metadata/types";
import { mediaTypeToJW } from "@/backend/metadata/justwatch";
export interface MediaCardProps {
media: MWMediaMeta;
@ -42,9 +43,9 @@ export function MediaCard(props: MediaCardProps) {
if (!props.linkable) return <span>{content}</span>;
return (
<Link
to={`/media/${encodeURIComponent(props.media.type)}-${encodeURIComponent(
props.media.id
)}`}
to={`/media/${encodeURIComponent(
mediaTypeToJW(props.media.type)
)}-${encodeURIComponent(props.media.id)}`}
>
{content}
</Link>

View File

@ -3,7 +3,7 @@ import { MWStream } from "@/backend/helpers/streams";
import { DetailedMeta } from "@/backend/metadata/getmeta";
import { useEffect, useState } from "react";
interface ScrapeEventLog {
export interface ScrapeEventLog {
type: "provider" | "embed";
errored: boolean;
percentage: number;

View File

@ -3,7 +3,7 @@ import { BookmarkContextProvider } from "@/state/bookmark";
import { WatchedContextProvider } from "@/state/watched";
import { NotFoundPage } from "@/views/notfound/NotFoundView";
import { MediaView } from "@/views/MediaView";
import { MediaView } from "@/views/media/MediaView";
import { SearchView } from "@/views/search/SearchView";
import { MWMediaType } from "@/backend/metadata/types";

View File

@ -0,0 +1,78 @@
import { Icon, Icons } from "@/components/Icon";
import { ScrapeEventLog } from "@/hooks/useScrape";
interface MediaScrapeLogProps {
events: ScrapeEventLog[];
}
interface MediaScrapePillProps {
event: ScrapeEventLog;
}
function MediaScrapePillSkeleton() {
return <div className="h-9 w-[220px] rounded-full bg-slate-800 opacity-50" />;
}
function MediaScrapePill({ event }: MediaScrapePillProps) {
return (
<div className="flex h-9 w-[220px] items-center rounded-full bg-slate-800 p-3 text-denim-700">
<div className="mr-2">
{!event.errored ? (
<svg className="h-[18px] w-[18px] -rotate-90" viewBox="0 0 100 100">
<circle
className="fill-transparent stroke-denim-700 stroke-[15] transition-[stroke-dashoffset] duration-150"
r="40"
cx="50"
cy="50"
style={{
strokeDasharray: `${2 * Math.PI * 40} ${2 * Math.PI * 40}`,
strokeDashoffset: `${
2 * Math.PI * 40 -
(event.percentage / 100) * (2 * Math.PI * 40)
}`,
}}
/>
</svg>
) : (
<Icon icon={Icons.X} className="text-[0.85em] text-rose-400" />
)}
</div>
<div className="flex-1 overflow-hidden">
<p
className={`overflow-hidden text-ellipsis whitespace-nowrap ${
event.errored ? "text-rose-400" : ""
}`}
>
{event.id}
</p>
</div>
</div>
);
}
export function MediaScrapeLog(props: MediaScrapeLogProps) {
return (
<div className="relative h-16 w-[400px] overflow-hidden">
<div className="absolute inset-0 flex items-center justify-center">
<div className="relative flex h-full w-[220px] items-center">
<div
className="absolute inset-y-0 left-0 flex items-center gap-[16px] transition-transform duration-200"
style={{
transform: `translateX(${
-1 * (220 + 16) * props.events.length
}px)`,
}}
>
<MediaScrapePillSkeleton />
{props.events.map((v) => (
<MediaScrapePill event={v} key={v.id} />
))}
<MediaScrapePillSkeleton />
</div>
</div>
</div>
<div className="absolute inset-y-0 left-0 w-40 bg-gradient-to-r from-denim-100 to-transparent" />
<div className="absolute inset-y-0 right-0 w-40 bg-gradient-to-l from-denim-100 to-transparent" />
</div>
);
}

View File

@ -7,9 +7,21 @@ import { VideoPlayerHeader } from "@/components/video/parts/VideoPlayerHeader";
import { DetailedMeta, getMetaFromId } from "@/backend/metadata/getmeta";
import { JWMediaToMediaType } from "@/backend/metadata/justwatch";
import { SourceControl } from "@/components/video/controls/SourceControl";
import { Loading } from "@/components/layout/Loading";
import { MediaScrapeLog } from "./MediaScrapeLog";
function MediaViewLoading() {
return <p>Loading meta...</p>;
function MediaViewLoading(props: { onGoBack(): void }) {
return (
<div className="relative flex h-screen items-center justify-center">
<div className="absolute inset-x-0 top-0 p-6">
<VideoPlayerHeader onClick={props.onGoBack} />
</div>
<div className="flex flex-col items-center">
<Loading className="mb-4" />
<p className="mb-8 text-denim-700">Finding the best video for you</p>
</div>
</div>
);
}
interface MediaViewScrapingProps {
@ -18,7 +30,7 @@ interface MediaViewScrapingProps {
meta: DetailedMeta;
}
function MediaViewScraping(props: MediaViewScrapingProps) {
const { eventLog, pending, stream } = useScrape(props.meta);
const { eventLog, stream } = useScrape(props.meta);
useEffect(() => {
if (stream) {
@ -26,24 +38,21 @@ function MediaViewScraping(props: MediaViewScrapingProps) {
}
}, [stream, props]);
// TODO error screen if no streams found
return (
<div>
<VideoPlayerHeader
onClick={props.onGoBack}
title={props.meta.meta.title}
/>
<p>pending: {pending.toString()}</p>
<p>
stream: {stream?.streamUrl} - {stream?.type} - {stream?.quality}
</p>
<hr />
{eventLog.map((v) => (
<div className="rounded-xl p-1 text-white">
<p>
{v.percentage}% - {v.type} - {v.errored ? "ERROR" : "pending"}
</p>
</div>
))}
<div className="relative flex h-screen items-center justify-center">
<div className="absolute inset-x-0 top-0 py-6 px-8">
<VideoPlayerHeader
onClick={props.onGoBack}
title={props.meta.meta.title}
/>
</div>
<div className="flex flex-col items-center">
<Loading className="mb-4" />
<p className="mb-8 text-denim-700">Finding the best video for you</p>
<MediaScrapeLog events={eventLog} />
</div>
</div>
);
}
@ -70,10 +79,9 @@ export function MediaView() {
}, [setMeta, params]);
// TODO watched store
// TODO scrape loading state
// TODO error page with video header
if (!meta) return <MediaViewLoading />;
if (!meta) return <MediaViewLoading onGoBack={goBack} />;
if (!stream)
return (
<MediaViewScraping meta={meta} onGoBack={goBack} onStream={setStream} />