Refactor media import handlers to utilize ManualInboxTaker for improved functionality
Updated the ImportManualInboxCommandHandler and ImportMoviesCommandHandler to replace direct storage interactions with the ManualInboxTaker, streamlining the import process. This change enhances code clarity and maintains consistency across media import functionalities. Additionally, refactored related tests to accommodate the new handler structure, ensuring robust testing of the import logic.
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Input } from '@/shared/ui/input'
|
||||
import { Label } from '@/shared/ui/label'
|
||||
|
||||
/**
|
||||
* Поля разбора серий: ручной сезон и regex номера. Один компонент на оба разбора — из `manual/`
|
||||
* и при загрузке файлов, — потому что правила у них общие: что показано в предпросмотре, то
|
||||
* и уедет на сервер, и расходиться этим двум местам нельзя.
|
||||
*/
|
||||
export function EpisodeParseFields({
|
||||
season,
|
||||
onSeason,
|
||||
regex,
|
||||
onRegex,
|
||||
regexOk,
|
||||
}: Readonly<{
|
||||
season: string
|
||||
onSeason: (value: string) => void
|
||||
regex: string
|
||||
onRegex: (value: string) => void
|
||||
/** Регулярка разбирается — иначе поле подсвечивается и снизу появляется объяснение. */
|
||||
regexOk: boolean
|
||||
}>) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-col gap-1.5">
|
||||
<Label>{t('admin.media.toShowSeason')}</Label>
|
||||
{/* Ноль — законный сезон: в нём живут спецвыпуски и пилоты. */}
|
||||
<Input
|
||||
type="number"
|
||||
min={0}
|
||||
placeholder={t('admin.media.toShowAuto')}
|
||||
value={season}
|
||||
onChange={(e) => onSeason(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1.5">
|
||||
<Label>{t('admin.media.toShowRegex')}</Label>
|
||||
<Input
|
||||
placeholder="^(\d+)"
|
||||
value={regex}
|
||||
onChange={(e) => onRegex(e.target.value)}
|
||||
className={!regexOk ? 'border-red-500' : undefined}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
parseSeasonFromFolder,
|
||||
} from './episode-parse'
|
||||
import { buildEpisodeRegex, findNumbers, REGEX_PRESETS } from './episode-regex'
|
||||
import { EpisodeParseFields } from './EpisodeParseFields'
|
||||
import { matchShowByName } from './match-show'
|
||||
|
||||
/** Байты → «1,4 ГБ»: в ручном разборе размер — главный ориентир, что это за файл. */
|
||||
@@ -250,26 +251,13 @@ export function ManualInboxPanel({ onClose }: Readonly<{ onClose: () => void }>)
|
||||
<Label>{t('common.search')}</Label>
|
||||
<Input value={query} onChange={(e) => setQuery(e.target.value)} />
|
||||
</div>
|
||||
<div className="flex flex-col gap-1.5">
|
||||
<Label>{t('admin.media.toShowSeason')}</Label>
|
||||
{/* Ноль — законный сезон: в нём живут спецвыпуски и пилоты. */}
|
||||
<Input
|
||||
type="number"
|
||||
min={0}
|
||||
placeholder={t('admin.media.toShowAuto')}
|
||||
value={seasonStr}
|
||||
onChange={(e) => setSeasonStr(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1.5">
|
||||
<Label>{t('admin.media.toShowRegex')}</Label>
|
||||
<Input
|
||||
placeholder="^(\d+)"
|
||||
value={regexStr}
|
||||
onChange={(e) => setRegexStr(e.target.value)}
|
||||
className={!regexOk ? 'border-red-500' : undefined}
|
||||
/>
|
||||
</div>
|
||||
<EpisodeParseFields
|
||||
season={seasonStr}
|
||||
onSeason={setSeasonStr}
|
||||
regex={regexStr}
|
||||
onRegex={setRegexStr}
|
||||
regexOk={regexOk}
|
||||
/>
|
||||
</div>
|
||||
{!regexOk && <p className="text-xs text-red-500">{t('admin.media.toShowRegexInvalid')}</p>}
|
||||
|
||||
|
||||
@@ -6,11 +6,10 @@ import { qk } from '@/shared/api/query-keys'
|
||||
import { Badge } from '@/shared/ui/badge'
|
||||
import { Button } from '@/shared/ui/button'
|
||||
import { DialogFooter } from '@/shared/ui/dialog'
|
||||
import { Input } from '@/shared/ui/input'
|
||||
import { Label } from '@/shared/ui/label'
|
||||
import { listShows } from '@/features/admin/shows/api'
|
||||
import { ShowPicker } from '@/features/admin/shows/ShowPicker'
|
||||
import { compareParsed, formatSeasonEpisode, isValidRegex, parseEpisodeName } from './episode-parse'
|
||||
import { EpisodeParseFields } from './EpisodeParseFields'
|
||||
import { matchShowByName } from './match-show'
|
||||
import { useUploadStore } from './upload-store'
|
||||
|
||||
@@ -101,25 +100,13 @@ export function UploadToShowPanel({ onClose }: Readonly<{ onClose: () => void }>
|
||||
|
||||
<div className="flex min-h-0 flex-1 flex-col gap-4">
|
||||
<div className="grid gap-3 sm:grid-cols-2">
|
||||
<div className="flex flex-col gap-1.5">
|
||||
<Label>{t('admin.media.toShowSeason')}</Label>
|
||||
<Input
|
||||
type="number"
|
||||
min={1}
|
||||
placeholder={t('admin.media.toShowAuto')}
|
||||
value={seasonStr}
|
||||
onChange={(e) => setSeasonStr(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1.5">
|
||||
<Label>{t('admin.media.toShowRegex')}</Label>
|
||||
<Input
|
||||
placeholder="^(\d+)"
|
||||
value={regexStr}
|
||||
onChange={(e) => setRegexStr(e.target.value)}
|
||||
className={!regexOk ? 'border-red-500' : undefined}
|
||||
/>
|
||||
</div>
|
||||
<EpisodeParseFields
|
||||
season={seasonStr}
|
||||
onSeason={setSeasonStr}
|
||||
regex={regexStr}
|
||||
onRegex={setRegexStr}
|
||||
regexOk={regexOk}
|
||||
/>
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{t('admin.media.toShowHint')}
|
||||
|
||||
Reference in New Issue
Block a user