summaryrefslogblamecommitdiffstatshomepage
path: root/frontend/src/lib/scraper/ComicScrapeForm.svelte
blob: 30ad89b52c5e9f8daa927560fa7b44c8004b995e (plain) (tree)









































































































































                                                                                                                                      
<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>