diff options
Diffstat (limited to 'frontend/src/lib/scraper/ComicScrapeForm.svelte')
-rw-r--r-- | frontend/src/lib/scraper/ComicScrapeForm.svelte | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/frontend/src/lib/scraper/ComicScrapeForm.svelte b/frontend/src/lib/scraper/ComicScrapeForm.svelte new file mode 100644 index 0000000..30ad89b --- /dev/null +++ b/frontend/src/lib/scraper/ComicScrapeForm.svelte @@ -0,0 +1,138 @@ +<script lang="ts"> + import { upsertComics } from '$gql/Mutations'; + import { comicScrapersQuery, scrapeComic } from '$gql/Queries'; + import { isError } from '$gql/Utils'; + import { OnMissing, type FullComicFragment } from '$gql/graphql'; + import { ScrapedComicSelector, getScraperContext } from '$lib/Scraper'; + import { toastError, toastFinally } from '$lib/Toasts'; + import Select from '$lib/components/Select.svelte'; + import Spinner from '$lib/components/Spinner.svelte'; + import { getContextClient } from '@urql/svelte'; + import SelectorGroup from './components/SelectorGroup.svelte'; + import SelectorItem from './components/SelectorItem.svelte'; + + let client = getContextClient(); + const context = getScraperContext(); + + export let comic: FullComicFragment; + let createMissing = false; + let loading = false; + + $: scrapersResult = comicScrapersQuery(client, { id: comic.id }); + $: scrapers = $scrapersResult.data?.comicScrapers; + + function scrape() { + loading = true; + scrapeComic(client, { id: comic.id, scraper: $context.scraper }) + .then((result) => { + if (result.error) { + toastError(result.error.message); + return; + } + + if (result.data) { + if (isError(result.data.scrapeComic)) { + toastError(result.data.scrapeComic.message); + return; + } + + if (result.data.scrapeComic.__typename === 'ScrapeComicResult') { + $context.selector = new ScrapedComicSelector(result.data.scrapeComic.data, comic); + $context.warnings = result.data.scrapeComic.warnings; + } + } + }) + .catch(toastFinally) + .finally(() => (loading = false)); + } + + function updateFromScrape(createMissing: boolean) { + if (!$context.selector) return; + + upsertComics(client, { + ids: comic.id, + input: $context.selector.toInput(createMissing ? OnMissing.Create : OnMissing.Ignore) + }) + .then(() => { + $context.selector = undefined; + $context.warnings = []; + }) + .catch(toastFinally); + } +</script> + +<div class="flex flex-col gap-4 text-sm"> + {#if scrapers && scrapers.length === 0} + <h2 class="text-base">No scrapers available.</h2> + {:else} + <form on:submit|preventDefault={scrape}> + <div class="grid grid-cols-6 gap-2"> + <div class="col-span-5"> + <Select + id="scrapers" + options={scrapers} + placeholder={'Select scraper...'} + bind:value={$context.scraper} + /> + </div> + <button type="submit" disabled={!$context.scraper} class="btn-blue">Scrape</button> + </div> + </form> + {/if} + + {#if loading} + <Spinner /> + {:else if $context.selector} + {#if $context.warnings.length > 0} + <div class="flex flex-col gap-2"> + <h2 class="flex gap-1 border-b border-slate-700 text-base font-medium">Warnings</h2> + <ul class="ml-2 list-inside list-disc"> + {#each $context.warnings as warning} + <li>{warning}</li> + {/each} + </ul> + </div> + {/if} + {#if !$context.selector.hasData()} + <h2 class="text-base">No data to merge.</h2> + {:else} + <div class="flex flex-col gap-2"> + <h2 class="border-b border-slate-700 text-base font-medium">Results</h2> + <form on:submit|preventDefault={() => updateFromScrape(createMissing)}> + <div class="grid grid-cols-6 gap-4 pb-2"> + <SelectorItem title="Title" selector={$context.selector.title} /> + <SelectorItem title="Original Title" selector={$context.selector.originalTitle} /> + <SelectorItem title="URL" selector={$context.selector.url} /> + <SelectorItem title="Date" selector={$context.selector.date} --span="2" /> + <SelectorItem title="Category" selector={$context.selector.category} --span="2" /> + <SelectorItem title="Language" selector={$context.selector.language} --span="2" /> + <SelectorItem title="Rating" selector={$context.selector.rating} --span="2" /> + <SelectorItem title="Censorship" selector={$context.selector.censorship} --span="2" /> + <SelectorItem title="Direction" selector={$context.selector.direction} --span="2" /> + <SelectorItem title="Layout" selector={$context.selector.layout} --span="2" /> + <SelectorGroup title="Artists" selectors={$context.selector.artists} /> + <SelectorGroup title="Circles" selectors={$context.selector.circles} /> + <SelectorGroup title="Characters" selectors={$context.selector.characters} /> + <SelectorGroup title="Worlds" selectors={$context.selector.worlds} /> + <SelectorGroup title="Tags" selectors={$context.selector.tags} /> + </div> + <div class="flex flex-col gap-2"> + <h2 class="border-b border-slate-700 text-base font-medium">Options</h2> + <div class="flex items-center gap-1"> + <input + class="h-4 w-4" + type="checkbox" + id="create-missing" + bind:checked={createMissing} + /> + <label class="shrink-0" for="create-missing">Create missing items</label> + </div> + </div> + <div class="flex gap-4"> + <button type="submit" class="btn-blue">Merge</button> + </div> + </form> + </div> + {/if} + {/if} +</div> |