diff options
Diffstat (limited to 'frontend/src/lib/Scraper.ts')
-rw-r--r-- | frontend/src/lib/Scraper.ts | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/frontend/src/lib/Scraper.ts b/frontend/src/lib/Scraper.ts new file mode 100644 index 0000000..4baf370 --- /dev/null +++ b/frontend/src/lib/Scraper.ts @@ -0,0 +1,156 @@ +import { + Category, + Censorship, + Direction, + Language, + Layout, + OnMissing, + Rating, + type FullComicFragment, + type ScrapedComic, + type UpsertComicInput, + type UpsertOptions +} from '$gql/graphql'; +import { + CategoryLabel, + CensorshipLabel, + DirectionLabel, + LanguageLabel, + LayoutLabel, + RatingLabel +} from '$lib/Enums'; +import { getContext, setContext } from 'svelte'; +import { writable, type Writable } from 'svelte/store'; + +interface ScraperContext { + scraper: string; + warnings: string[]; + selector?: ScrapedComicSelector; +} + +export function initScraperContext() { + return setContext<Writable<ScraperContext>>('scraper', writable({ scraper: '', warnings: [] })); +} + +export function getScraperContext() { + return getContext<Writable<ScraperContext>>('scraper'); +} + +export class Selector<T extends string> { + keep = true; + value: T; + display: string | undefined; + + constructor(value: T, display?: string) { + this.value = value; + this.display = display; + } + + toString() { + return this.display ?? this.value; + } + + static from<T extends string>( + scraped: T | undefined | null, + have: string | undefined | null, + label?: Record<string, string> + ) { + if (scraped && have !== scraped) { + return new Selector(scraped, label ? label[scraped] : undefined); + } + return undefined; + } + + static fromList(scraped: string[], have: { name: string }[]) { + const haves = new Set(have.map((i) => i.name)); + + return scraped.filter((i) => !haves.has(i)).map((i) => new Selector(i)); + } +} + +function keepItem<T extends string>(selector?: Selector<T>): T | undefined | null { + if (selector?.keep) { + return selector.value; + } + return undefined; +} + +function keepList<T extends string>( + selectorList: Selector<T>[], + onMissing: OnMissing +): { names: T[]; options: UpsertOptions } { + return { + names: selectorList.filter((v) => v.keep).map((v) => v.value), + options: { onMissing } + }; +} + +export class ScrapedComicSelector { + title?: Selector<string>; + originalTitle?: Selector<string>; + url?: Selector<string>; + date?: Selector<string>; + category?: Selector<Category>; + censorship?: Selector<Censorship>; + rating?: Selector<Rating>; + language?: Selector<Language>; + direction?: Selector<Direction>; + layout?: Selector<Layout>; + artists: Selector<string>[]; + circles: Selector<string>[]; + characters: Selector<string>[]; + worlds: Selector<string>[]; + tags: Selector<string>[]; + + constructor(scraped: ScrapedComic, comic: FullComicFragment) { + this.title = Selector.from(scraped.title, comic.title); + this.originalTitle = Selector.from(scraped.originalTitle, comic.originalTitle); + this.url = Selector.from(scraped.url, comic.url); + this.date = Selector.from(scraped.date, comic.date); + this.category = Selector.from(scraped.category, comic.category, CategoryLabel); + this.censorship = Selector.from(scraped.censorship, comic.censorship, CensorshipLabel); + this.rating = Selector.from(scraped.rating, comic.rating, RatingLabel); + this.language = Selector.from(scraped.language, comic.language, LanguageLabel); + this.direction = Selector.from(scraped.direction, comic.direction, DirectionLabel); + this.layout = Selector.from(scraped.layout, comic.layout, LayoutLabel); + + this.artists = Selector.fromList(scraped.artists, comic.artists); + this.circles = Selector.fromList(scraped.circles, comic.circles); + this.characters = Selector.fromList(scraped.characters, comic.characters); + this.tags = Selector.fromList(scraped.tags, comic.tags); + this.worlds = Selector.fromList(scraped.worlds, comic.worlds); + } + + hasData() { + return ( + Object.values(this).filter((i) => { + if (i === undefined) { + return false; + } else if (Array.isArray(i) && i.length === 0) { + return false; + } + return true; + }).length > 0 + ); + } + + toInput(onMissing: OnMissing): UpsertComicInput { + return { + title: keepItem(this.title), + originalTitle: keepItem(this.originalTitle), + url: keepItem(this.url), + date: keepItem(this.date), + category: keepItem(this.category), + censorship: keepItem(this.censorship), + rating: keepItem(this.rating), + language: keepItem(this.language), + direction: keepItem(this.direction), + layout: keepItem(this.layout), + artists: keepList(this.artists, onMissing), + circles: keepList(this.circles, onMissing), + characters: keepList(this.characters, onMissing), + worlds: keepList(this.worlds, onMissing), + tags: keepList(this.tags, onMissing) + }; + } +} |