Add original name support for shows: implement API endpoint to set original name, update Show and ShowDto models to include original name field, and enhance UI components for managing original names in show metadata. Update validation and database schema accordingly.
This commit is contained in:
@@ -15,6 +15,7 @@ import {
|
||||
getMetadataProviders,
|
||||
refreshEpisodesMetadata,
|
||||
searchMetadata,
|
||||
setShowOriginalName,
|
||||
showPosterUrl,
|
||||
updateMetadata,
|
||||
uploadPoster,
|
||||
@@ -25,7 +26,8 @@ export function ShowMetadataCard({ show, onChanged }: { show: ShowDto; onChanged
|
||||
const posterInput = useRef<HTMLInputElement>(null)
|
||||
const [bust, setBust] = useState(0)
|
||||
const [provider, setProvider] = useState('')
|
||||
const [query, setQuery] = useState(show.name)
|
||||
const [originalName, setOriginalName] = useState(show.originalName ?? '')
|
||||
const [query, setQuery] = useState(show.originalName || show.name)
|
||||
const [results, setResults] = useState<MetadataCandidate[]>([])
|
||||
const [searched, setSearched] = useState(false)
|
||||
const [description, setDescription] = useState(show.description ?? '')
|
||||
@@ -53,6 +55,15 @@ export function ShowMetadataCard({ show, onChanged }: { show: ShowDto; onChanged
|
||||
},
|
||||
onError,
|
||||
})
|
||||
const saveOriginal = useMutation({
|
||||
mutationFn: () => setShowOriginalName(show.id, originalName.trim() || null),
|
||||
onSuccess: () => {
|
||||
toast.success(t('settings.saved'))
|
||||
setQuery(originalName.trim() || show.name)
|
||||
onChanged()
|
||||
},
|
||||
onError,
|
||||
})
|
||||
const apply = useMutation({
|
||||
mutationFn: (externalId: string) => applyMetadata(show.id, effectiveProvider, externalId),
|
||||
onSuccess: () => {
|
||||
@@ -143,6 +154,28 @@ export function ShowMetadataCard({ show, onChanged }: { show: ShowDto; onChanged
|
||||
|
||||
{/* Поиск + ручная правка */}
|
||||
<div className="flex min-w-0 flex-1 flex-col gap-4">
|
||||
<div className="flex flex-col gap-1.5">
|
||||
<Label>{t('admin.metadata.originalName')}</Label>
|
||||
<div className="flex items-end gap-2">
|
||||
<Input
|
||||
className="min-w-40 flex-1"
|
||||
value={originalName}
|
||||
maxLength={256}
|
||||
placeholder={t('admin.metadata.originalNamePlaceholder')}
|
||||
onChange={(e) => setOriginalName(e.target.value)}
|
||||
/>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
disabled={saveOriginal.isPending || originalName === (show.originalName ?? '')}
|
||||
onClick={() => saveOriginal.mutate()}
|
||||
>
|
||||
{t('common.save')}
|
||||
</Button>
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground">{t('admin.metadata.originalNameHint')}</p>
|
||||
</div>
|
||||
|
||||
{providers && providers.length > 0 && (
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex flex-wrap items-end gap-2">
|
||||
|
||||
@@ -15,6 +15,7 @@ export function ShowsPanel() {
|
||||
const { t } = useTranslation()
|
||||
const queryClient = useQueryClient()
|
||||
const [name, setName] = useState('')
|
||||
const [originalName, setOriginalName] = useState('')
|
||||
const [kind, setKind] = useState<ShowKind>('Series')
|
||||
|
||||
const { data, isLoading } = useQuery({ queryKey: ['admin', 'shows'], queryFn: listShows })
|
||||
@@ -23,9 +24,11 @@ export function ShowsPanel() {
|
||||
toast.error(error instanceof HttpError ? error.detail : t('common.error'))
|
||||
|
||||
const createMutation = useMutation({
|
||||
mutationFn: () => createShow({ name: name.trim(), kind }),
|
||||
mutationFn: () =>
|
||||
createShow({ name: name.trim(), kind, originalName: originalName.trim() || undefined }),
|
||||
onSuccess: () => {
|
||||
setName('')
|
||||
setOriginalName('')
|
||||
invalidate()
|
||||
},
|
||||
onError,
|
||||
@@ -43,6 +46,12 @@ export function ShowsPanel() {
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
/>
|
||||
<Input
|
||||
className="max-w-xs"
|
||||
placeholder={t('admin.shows.originalName')}
|
||||
value={originalName}
|
||||
onChange={(e) => setOriginalName(e.target.value)}
|
||||
/>
|
||||
<Select value={kind} onValueChange={(v) => setKind(v as ShowKind)}>
|
||||
<SelectTrigger className="w-40">
|
||||
<SelectValue />
|
||||
|
||||
@@ -15,10 +15,22 @@ export function getShow(id: string) {
|
||||
return apiRequest<ShowDto>(`/admin/shows/${id}`)
|
||||
}
|
||||
|
||||
export function createShow(body: { name: string; kind: ShowKind; description?: string }) {
|
||||
export function createShow(body: {
|
||||
name: string
|
||||
kind: ShowKind
|
||||
description?: string
|
||||
originalName?: string
|
||||
}) {
|
||||
return apiRequest<CreatedIdResponse>('/admin/shows', { method: 'POST', body })
|
||||
}
|
||||
|
||||
export function setShowOriginalName(id: string, originalName: string | null) {
|
||||
return apiRequest<void>(`/admin/shows/${id}/original-name`, {
|
||||
method: 'PUT',
|
||||
body: { originalName },
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteShow(id: string) {
|
||||
return apiRequest<void>(`/admin/shows/${id}`, { method: 'DELETE' })
|
||||
}
|
||||
|
||||
@@ -102,6 +102,7 @@ export type EpisodeDto = {
|
||||
export type ShowDto = {
|
||||
id: string
|
||||
name: string
|
||||
originalName: string | null
|
||||
kind: ShowKind
|
||||
description: string | null
|
||||
metadataProvider: string | null
|
||||
|
||||
@@ -152,6 +152,7 @@ const resources = {
|
||||
shows: {
|
||||
title: 'Шоу',
|
||||
name: 'Название',
|
||||
originalName: 'Оригинальное название (eng)',
|
||||
kind: 'Тип',
|
||||
kinds: { Series: 'Сериал', Single: 'Полнометражка' },
|
||||
seasons: 'Сезоны',
|
||||
@@ -268,6 +269,9 @@ const resources = {
|
||||
},
|
||||
metadata: {
|
||||
title: 'Метаданные',
|
||||
originalName: 'Оригинальное название (eng)',
|
||||
originalNamePlaceholder: 'Например: Family Guy',
|
||||
originalNameHint: 'По нему ищутся метаданные; на экранах показывается обычное название.',
|
||||
source: 'Источник',
|
||||
sourceLabel: 'Источник',
|
||||
searchPlaceholder: 'Название для поиска',
|
||||
@@ -437,6 +441,7 @@ const resources = {
|
||||
shows: {
|
||||
title: 'Shows',
|
||||
name: 'Name',
|
||||
originalName: 'Original name (eng)',
|
||||
kind: 'Kind',
|
||||
kinds: { Series: 'Series', Single: 'Movie' },
|
||||
seasons: 'Seasons',
|
||||
@@ -553,6 +558,9 @@ const resources = {
|
||||
},
|
||||
metadata: {
|
||||
title: 'Metadata',
|
||||
originalName: 'Original name (eng)',
|
||||
originalNamePlaceholder: 'e.g. Family Guy',
|
||||
originalNameHint: 'Metadata is looked up by this; screens still show the regular name.',
|
||||
source: 'Source',
|
||||
sourceLabel: 'Source',
|
||||
searchPlaceholder: 'Title to search',
|
||||
|
||||
Reference in New Issue
Block a user