import React, { useEffect } from 'react' import { Box, Paper, Typography, TextField, MenuItem, FormControlLabel, Switch, Collapse, IconButton, Divider, Alert, } from '@mui/material' 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 children: React.ReactNode defaultExpanded?: boolean } const Section: React.FC = ({ title, children, defaultExpanded = false }) => { const [expanded, setExpanded] = React.useState(defaultExpanded) return ( setExpanded(!expanded)} > {title} {expanded ? : } {children} ) } export const OptionsPanel: React.FC = () => { const { options, setOptions } = useOptionsStore() const { hasVideo } = useUploadStore() const { formatError, setFormatError } = useValidationStore() // Audio-only formats from backend constants (hardcoded for now) const audioOnlyFormats = ['mp3', 'm4a', 'ogg', 'opus', 'flac', 'wav', 'aac'] const handleFormatChange = (e: React.ChangeEvent) => { 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) => { 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 ( ⚙️ Options {formatError && ( {formatError} )} {/* Output Settings */}
MP3 M4A MKV MP4 OGG OPUS FLAC WAV AAC handleChange('transcode_to', e.target.value || undefined)} fullWidth size="small" > Copy (no transcoding) MP3 (LAME) AAC OPUS {hasVideo && ( } label="Drop video streams" /> )} handleChange('drop_subs', e.target.checked)} /> } label="Drop subtitle streams" />
{/* Filename Settings */}
handleChange('output_template', e.target.value)} fullWidth size="small" helperText="Placeholders: %tn (track name), %an (author), %al (album), %date, %ext, %num" /> handleChange('number_tracks', e.target.checked)} /> } label="Number tracks (01 - )" /> handleChange('replace_bad_chars', e.target.checked)} /> } label="Replace bad characters" /> handleChange('replacement_char', e.target.value)} size="small" disabled={!options.replace_bad_chars} /> handleChange('bad_chars', e.target.value)} fullWidth size="small" disabled={!options.replace_bad_chars} /> handleChange('skip_existing', e.target.checked)} /> } label="Skip existing files" />
{/* Metadata Settings */}
handleChange('album', e.target.value)} fullWidth size="small" /> handleChange('comment', e.target.value)} fullWidth size="small" /> handleChange('no_comment', e.target.checked)} /> } label="No comment" /> handleChange('comment_stream', e.target.value === '' ? null : parseInt(e.target.value)) } size="small" disabled={options.no_comment} /> handleChange('merge_comments', e.target.checked)} /> } label="Merge all comments" disabled={options.no_comment} /> handleChange('comment_separator', e.target.value)} size="small" disabled={!options.merge_comments || options.no_comment} />
{/* Tracklist Settings */}
handleChange('tracklist_format', e.target.value)} fullWidth size="small" helperText="Placeholders: %ts (timestamp), %tn (track name), %an (author), %al (album), %date, %ext" />
) // Helper function for option updates function handleChange(field: string, value: any) { setOptions({ [field]: value }) } }