Tracs validation added. A warning is thrown if the input contains a video strem, but the requested output format doesn't support it

This commit is contained in:
2026-08-03 11:26:17 +05:00
parent 1d1f8563c0
commit dcdae41706
11 changed files with 330 additions and 52 deletions
+88 -33
View File
@@ -1,4 +1,4 @@
import React from 'react'
import React, { useEffect } from 'react'
import {
Box,
Paper,
@@ -10,11 +10,12 @@ import {
Collapse,
IconButton,
Divider,
Alert,
} from '@mui/material'
// Select is used internally by TextField with select prop, no need to import
import { ExpandMore, ExpandLess } from '@mui/icons-material'
import { useOptionsStore } from '../stores/optionsStore'
import { useUploadStore } from '../stores/uploadStore'
import { useValidationStore } from '../stores/validationStore'
interface SectionProps {
title: string
@@ -52,41 +53,75 @@ const Section: React.FC<SectionProps> = ({ title, children, defaultExpanded = fa
export const OptionsPanel: React.FC = () => {
const { options, setOptions } = useOptionsStore()
const { hasVideo } = useUploadStore()
const { formatError, setFormatError } = useValidationStore()
const handleChange = (field: string, value: any) => {
setOptions({ [field]: value })
// Audio-only formats from backend constants (hardcoded for now)
const audioOnlyFormats = ['mp3', 'm4a', 'ogg', 'opus', 'flac', 'wav', 'aac']
const handleFormatChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newFormat = e.target.value
setOptions({ format: newFormat })
// Validate format
if (audioOnlyFormats.includes(newFormat) && hasVideo && !options.drop_video) {
setFormatError(
`Format '${newFormat}' does not support video streams. Please enable "Drop video" or choose a container that supports video (e.g., MKV, MP4).`
)
} else {
setFormatError(null)
}
}
const handleDropVideoChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const checked = e.target.checked
setOptions({ drop_video: checked })
// Re-validate format
if (audioOnlyFormats.includes(options.format) && hasVideo && !checked) {
setFormatError(
`Format '${options.format}' does not support video streams. Please enable "Drop video" or choose a container that supports video (e.g., MKV, MP4).`
)
} else {
setFormatError(null)
}
}
// Re-validate when hasVideo changes (e.g., after upload)
useEffect(() => {
const shouldShowError = audioOnlyFormats.includes(options.format) && hasVideo && !options.drop_video
const newError = shouldShowError
? `Format '${options.format}' does not support video streams. Please enable "Drop video" or choose a container that supports video (e.g., MKV, MP4).`
: null
// Only update if the error state actually changes
if (newError !== formatError) {
setFormatError(newError)
}
}, [hasVideo, options.format, options.drop_video, formatError, setFormatError])
return (
<Paper sx={{ p: 3 }}>
<Typography variant="h6" sx={{ mb: 2 }}>
Options
</Typography>
{/* Tracklist Section */}
<Section title="Tracklist Settings" defaultExpanded>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
<TextField
label="Tracklist Format"
value={options.tracklist_format}
onChange={(e) => handleChange('tracklist_format', e.target.value)}
fullWidth
size="small"
helperText="Placeholders: %ts (timestamp), %tn (track name), %an (author), %al (album), %date, %ext"
/>
</Box>
</Section>
{formatError && (
<Alert severity="warning" sx={{ mb: 2 }}>
{formatError}
</Alert>
)}
{/* Output Section */}
{/* Output Settings */}
<Section title="Output Settings" defaultExpanded>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
<TextField
label="Format"
select
value={options.format}
onChange={(e) => handleChange('format', e.target.value)}
onChange={handleFormatChange}
fullWidth
size="small"
error={!!formatError}
>
<MenuItem value="mp3">MP3</MenuItem>
<MenuItem value="m4a">M4A</MenuItem>
@@ -113,15 +148,18 @@ export const OptionsPanel: React.FC = () => {
<MenuItem value="libopus">OPUS</MenuItem>
</TextField>
<FormControlLabel
control={
<Switch
checked={options.drop_video}
onChange={(e) => handleChange('drop_video', e.target.checked)}
/>
}
label="Drop video streams"
/>
{hasVideo && (
<FormControlLabel
control={
<Switch
checked={options.drop_video}
onChange={handleDropVideoChange}
/>
}
label="Drop video streams"
/>
)}
<FormControlLabel
control={
<Switch
@@ -134,7 +172,7 @@ export const OptionsPanel: React.FC = () => {
</Box>
</Section>
{/* Filename Section */}
{/* Filename Settings */}
<Section title="Filename Settings">
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
<TextField
@@ -190,7 +228,7 @@ export const OptionsPanel: React.FC = () => {
</Box>
</Section>
{/* Metadata Section */}
{/* Metadata Settings */}
<Section title="Metadata Settings">
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
<TextField
@@ -245,8 +283,25 @@ export const OptionsPanel: React.FC = () => {
/>
</Box>
</Section>
{/* Tracklist Settings */}
<Section title="Tracklist Settings" defaultExpanded>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
<TextField
label="Tracklist Format"
value={options.tracklist_format}
onChange={(e) => handleChange('tracklist_format', e.target.value)}
fullWidth
size="small"
helperText="Placeholders: %ts (timestamp), %tn (track name), %an (author), %al (album), %date, %ext"
/>
</Box>
</Section>
</Paper>
)
// Helper function for option updates
function handleChange(field: string, value: any) {
setOptions({ [field]: value })
}
}