Files
MeBox/web/src/components/ManualScrapeDialogModel.ts
T
2026-06-25 06:13:59 +08:00

91 lines
2.8 KiB
TypeScript

import type { ManualScrapeCandidate } from '../api/library'
import type { Media } from '../types'
export interface ManualSearchProvider {
value: string
label: string
}
export const manualSearchProviders: ManualSearchProvider[] = [
{ value: 'tmdb', label: 'TMDb' },
{ value: 'douban', label: '豆瓣' },
{ value: 'bangumi', label: 'Bangumi' },
{ value: 'thetvdb', label: 'TheTVDB' },
{ value: 'adult', label: 'Adult / 番号' },
]
export function candidateKey(item: ManualScrapeCandidate): string {
return `${item.source}:${item.tmdb_id || item.bangumi_id || item.douban_id || item.thetvdb_id || item.title}:${item.media_type || ''}`
}
export function manualSearchProvidersForSelection(selectedProviders: string[], query: string): string[] {
const explicitProvider = providerFromQueryPrefix(query)
if (explicitProvider) return [explicitProvider]
return selectedProviders.length > 0 ? selectedProviders : manualSearchProviders.map((provider) => provider.value)
}
export function toggleProvider(current: string[], value: string): string[] {
if (current.includes(value)) {
return current.filter((item) => item !== value)
}
const next = [...current, value]
return next.length === manualSearchProviders.length ? [] : next
}
export function mergeManualCandidates(
current: ManualScrapeCandidate[],
incoming: ManualScrapeCandidate[],
): ManualScrapeCandidate[] {
if (incoming.length === 0) return current
const byKey = new Map(current.map((item) => [candidateKey(item), item]))
for (const item of incoming) {
byKey.set(candidateKey(item), item)
}
return Array.from(byKey.values())
}
export function isEpisodeArtworkTarget(media: Media, mediaType?: string, targetCount = 1): boolean {
const type = (mediaType || '').toLowerCase()
return (
type === 'tv' ||
type === 'anime' ||
type === 'variety' ||
media.season_num > 0 ||
media.episode_num > 0 ||
targetCount > 1
)
}
export function candidateIDText(item: ManualScrapeCandidate): string {
const parts = [
item.tmdb_id ? `TMDb ${item.tmdb_id}` : '',
item.original_name && item.source === 'adult' ? `番号 ${item.original_name}` : '',
item.douban_id ? `豆瓣 ${item.douban_id}` : '',
item.bangumi_id ? `Bangumi ${item.bangumi_id}` : '',
item.thetvdb_id ? `TheTVDB ${item.thetvdb_id}` : '',
item.media_type ? item.media_type : '',
].filter(Boolean)
return parts.join(' · ')
}
function providerFromQueryPrefix(query: string): string {
const prefix = query.trim().toLowerCase().match(/^([a-z]+)\s*:/)?.[1]
switch (prefix) {
case 'tmdb':
return 'tmdb'
case 'douban':
return 'douban'
case 'bangumi':
case 'bgm':
return 'bangumi'
case 'thetvdb':
case 'tvdb':
return 'thetvdb'
case 'adult':
case 'jav':
return 'adult'
default:
return ''
}
}