import { Check, LoaderCircle, Search, Sparkles, X } from 'lucide-react'
import { imageURL } from '../api/client'
import type { ManualScrapeCandidate } from '../api/library'
import {
candidateIDText,
candidateKey,
manualSearchProviders,
toggleProvider,
} from './ManualScrapeDialogModel'
import { EpisodeArtworkToggle } from './EpisodeArtworkToggle'
export function ManualScrapeDialogHeader({
title,
targetCount,
onClose,
}: {
title: string
targetCount: number
onClose: () => void
}) {
return (
手动搜索刮削
{title} · {targetCount > 1 ? `将应用到 ${targetCount} 个媒体` : '单个媒体'}
)
}
interface ManualScrapeSearchControlsProps {
query: string
selectedProviders: string[]
searching: boolean
includeEpisodeArtwork: boolean
showEpisodeArtworkToggle: boolean
onQueryChange: (value: string) => void
onProviderChange: (value: string[] | ((current: string[]) => string[])) => void
onSearch: () => void
onEpisodeArtworkChange: (checked: boolean) => void
}
export function ManualScrapeSearchControls({
query,
selectedProviders,
searching,
includeEpisodeArtwork,
showEpisodeArtworkToggle,
onQueryChange,
onProviderChange,
onSearch,
onEpisodeArtworkChange,
}: ManualScrapeSearchControlsProps) {
return (
{showEpisodeArtworkToggle && (
)}
)
}
function ProviderSelector({
selectedProviders,
onProviderChange,
}: {
selectedProviders: string[]
onProviderChange: (value: string[] | ((current: string[]) => string[])) => void
}) {
return (
刮削源
{manualSearchProviders.map((item) => {
const active = selectedProviders.includes(item.value)
return (
)
})}
)
}
function ManualScrapeQueryBar({
query,
searching,
onQueryChange,
onSearch,
}: {
query: string
searching: boolean
onQueryChange: (value: string) => void
onSearch: () => void
}) {
return (
)
}
export function ManualScrapeCandidateList({
items,
applyingKey,
onApply,
}: {
items: ManualScrapeCandidate[]
applyingKey: string
onApply: (item: ManualScrapeCandidate) => void
}) {
if (items.length === 0) {
return (
搜索后在这里选择正确的元数据
)
}
return (
{items.map((item) => {
const key = candidateKey(item)
return (
)
})}
)
}
function ManualScrapeCandidateRow({
item,
applying,
disabled,
onApply,
}: {
item: ManualScrapeCandidate
applying: boolean
disabled: boolean
onApply: (item: ManualScrapeCandidate) => void
}) {
return (
{item.poster_url ? (
})
) : (
无海报
)}
{item.title}
{item.source}
{item.nsfw ? 成人 : null}
{item.year ? {item.year} : null}
{item.overview || '暂无简介'}
{candidateIDText(item)}
)
}
function providerButtonClass(active: boolean): string {
return (
'inline-flex h-9 min-w-0 shrink-0 items-center justify-center gap-1.5 rounded-lg border px-3 text-xs font-bold transition ' +
(active
? 'border-brand-300 bg-brand-50 text-brand-700'
: 'border-sand-200 bg-white text-sand-600 hover:border-brand-200 hover:text-brand-600')
)
}