mirror of
https://github.com/sussy-code/smov.git
synced 2024-12-29 16:07:40 +01:00
Error handling of providers + search suffix
This commit is contained in:
parent
8f76a5745f
commit
95ef071f59
5 changed files with 119 additions and 15 deletions
|
@ -33,10 +33,10 @@ Check out [this project's issues](https://github.com/JamesHawkinss/movie-web/iss
|
|||
|
||||
## Rewrite TODO's
|
||||
|
||||
- [ ] Better provider errors (only fail if all failed, show individual fails somewhere)
|
||||
- [ ] Better no results view
|
||||
- [x] Better provider errors (only fail if all failed, show individual fails somewhere)
|
||||
- [ ] Better search suffix view
|
||||
- [ ] Add back link of results view
|
||||
- [ ] Add results list end
|
||||
- [x] Add results list end
|
||||
- [ ] Add Brand tag top left
|
||||
- [ ] Add github and discord top right
|
||||
- [ ] Store watched percentage
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import { tempScraper } from "./list/temp";
|
||||
import { theFlixScraper } from "./list/theflix";
|
||||
import { MWMedia, MWMediaType, MWPortableMedia, MWQuery } from "./types";
|
||||
import { MWMassProviderOutput, MWMedia, MWMediaType, MWPortableMedia, MWQuery } from "./types";
|
||||
import { MWWrappedMediaProvider, WrapProvider } from "./wrapper";
|
||||
export * from "./types";
|
||||
|
||||
const mediaProvidersUnchecked: MWWrappedMediaProvider[] = [
|
||||
WrapProvider(theFlixScraper),
|
||||
WrapProvider(tempScraper),
|
||||
];
|
||||
export const mediaProviders: MWWrappedMediaProvider[] =
|
||||
mediaProvidersUnchecked.filter((v) => v.enabled);
|
||||
|
@ -19,12 +21,38 @@ export function GetProvidersForType(type: MWMediaType) {
|
|||
/*
|
||||
** Call search on all providers that matches query type
|
||||
*/
|
||||
export async function SearchProviders(query: MWQuery): Promise<MWMedia[]> {
|
||||
const allQueries = GetProvidersForType(query.type).map((provider) =>
|
||||
provider.searchForMedia(query)
|
||||
);
|
||||
export async function SearchProviders(query: MWQuery): Promise<MWMassProviderOutput> {
|
||||
const allQueries = GetProvidersForType(query.type).map<Promise<{ media: MWMedia[], success: boolean, id: string, }>>(async (provider) => {
|
||||
try {
|
||||
return {
|
||||
media: await provider.searchForMedia(query),
|
||||
success: true,
|
||||
id: provider.id,
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`Failed running provider ${provider.id}`, err, query);
|
||||
return {
|
||||
media: [],
|
||||
success: false,
|
||||
id: provider.id,
|
||||
}
|
||||
}
|
||||
});
|
||||
const allResults = await Promise.all(allQueries);
|
||||
return allResults.flatMap((results) => results);
|
||||
const providerResults = allResults.map(provider => ({ success: provider.success, id: provider.id }));
|
||||
const output = {
|
||||
results: allResults.flatMap((results) => results.media),
|
||||
providers: providerResults,
|
||||
stats: {
|
||||
total: providerResults.length,
|
||||
failed: providerResults.filter(v=>!v.success).length,
|
||||
succeeded: providerResults.filter(v=>v.success).length,
|
||||
},
|
||||
};
|
||||
|
||||
if (output.stats.total === output.stats.failed)
|
||||
throw new Error("All Scrapers failed");
|
||||
return output;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
30
src/providers/list/temp/index.ts
Normal file
30
src/providers/list/temp/index.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
import {
|
||||
MWMediaProvider,
|
||||
MWMediaType,
|
||||
MWPortableMedia,
|
||||
MWQuery,
|
||||
} from "providers/types";
|
||||
|
||||
import { MWProviderMediaResult } from "providers";
|
||||
|
||||
export const tempScraper: MWMediaProvider = {
|
||||
id: "temp",
|
||||
enabled: true,
|
||||
type: [MWMediaType.MOVIE, MWMediaType.SERIES],
|
||||
displayName: "temp",
|
||||
|
||||
async getMediaFromPortable(
|
||||
media: MWPortableMedia
|
||||
): Promise<MWProviderMediaResult> {
|
||||
return {
|
||||
...media,
|
||||
year: "1234",
|
||||
title: "temp",
|
||||
};
|
||||
},
|
||||
|
||||
async searchForMedia(query: MWQuery): Promise<MWProviderMediaResult[]> {
|
||||
|
||||
return [];
|
||||
},
|
||||
};
|
|
@ -33,3 +33,16 @@ export interface MWMediaProvider {
|
|||
getMediaFromPortable(media: MWPortableMedia): Promise<MWProviderMediaResult>;
|
||||
searchForMedia(query: MWQuery): Promise<MWProviderMediaResult[]>;
|
||||
}
|
||||
|
||||
export interface MWMassProviderOutput {
|
||||
providers: {
|
||||
id: string,
|
||||
success: boolean,
|
||||
}[];
|
||||
results: MWMedia[],
|
||||
stats: {
|
||||
total: number,
|
||||
failed: number,
|
||||
succeeded: number,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
import { WatchedMediaCard } from "components/media/WatchedMediaCard";
|
||||
import { SearchBarInput } from "components/SearchBar";
|
||||
import { MWMedia, MWMediaType, MWQuery, SearchProviders } from "providers";
|
||||
import {
|
||||
MWMassProviderOutput,
|
||||
MWMedia,
|
||||
MWMediaType,
|
||||
MWQuery,
|
||||
SearchProviders,
|
||||
} from "providers";
|
||||
import { useEffect, useState } from "react";
|
||||
import { ThinContainer } from "components/layout/ThinContainer";
|
||||
import { SectionHeading } from "components/layout/SectionHeading";
|
||||
|
@ -15,8 +21,29 @@ function SearchLoading() {
|
|||
return <Loading className="my-12" text="Fetching your favourite shows..." />;
|
||||
}
|
||||
|
||||
function SearchSuffix(props: {
|
||||
fails: number;
|
||||
total: number;
|
||||
resultsSize: number;
|
||||
}) {
|
||||
return (
|
||||
<div>
|
||||
{props.fails > 0 ? (
|
||||
<p>
|
||||
{props.fails}/{props.total} providers failed
|
||||
</p>
|
||||
) : null}
|
||||
{props.resultsSize > 0 ? (
|
||||
<p>Thats all we have to show</p>
|
||||
) : (
|
||||
<p>No results to show</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function SearchResultsView({ searchQuery }: { searchQuery: MWQuery }) {
|
||||
const [results, setResults] = useState<MWMedia[]>([]);
|
||||
const [results, setResults] = useState<MWMassProviderOutput | undefined>();
|
||||
const [runSearchQuery, loading, error, success] = useLoading(
|
||||
(query: MWQuery) => SearchProviders(query)
|
||||
);
|
||||
|
@ -34,9 +61,9 @@ function SearchResultsView({ searchQuery }: { searchQuery: MWQuery }) {
|
|||
return (
|
||||
<div>
|
||||
{/* results */}
|
||||
{success && results.length > 0 ? (
|
||||
{success && results?.results.length ? (
|
||||
<SectionHeading title="Search results" icon={Icons.SEARCH}>
|
||||
{results.map((v) => (
|
||||
{results.results.map((v) => (
|
||||
<WatchedMediaCard
|
||||
key={[v.mediaId, v.providerId].join("|")}
|
||||
media={v}
|
||||
|
@ -45,8 +72,14 @@ function SearchResultsView({ searchQuery }: { searchQuery: MWQuery }) {
|
|||
</SectionHeading>
|
||||
) : null}
|
||||
|
||||
{/* no results */}
|
||||
{success && results.length === 0 ? <p>No results found</p> : null}
|
||||
{/* search suffix */}
|
||||
{success && results ? (
|
||||
<SearchSuffix
|
||||
resultsSize={results.results.length}
|
||||
fails={results.stats.failed}
|
||||
total={results.stats.total}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{/* error */}
|
||||
{error ? <p>All scrapers failed</p> : null}
|
||||
|
|
Loading…
Reference in a new issue