Frontend and backend work together fine, complete workflow is implemented
This commit is contained in:
@@ -62,6 +62,20 @@ export const OptionsPanel: React.FC = () => {
|
||||
⚙️ 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>
|
||||
|
||||
{/* Output Section */}
|
||||
<Section title="Output Settings" defaultExpanded>
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
|
||||
@@ -232,4 +246,6 @@ export const OptionsPanel: React.FC = () => {
|
||||
</Section>
|
||||
</Paper>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,29 +2,28 @@ import React, { useCallback, useEffect, useState } from 'react'
|
||||
import { Box, Paper, TextField, Typography, Alert } from '@mui/material'
|
||||
import { useDropzone } from 'react-dropzone'
|
||||
import { useTracklistStore } from '../stores/tracklistStore'
|
||||
import { validateTracklist, parseTracklist } from '../utils/validators'
|
||||
import { useOptionsStore } from '../stores/optionsStore'
|
||||
import { parseAndValidateTracklist } from '../utils/validators'
|
||||
import { TracklistEntry } from '../types'
|
||||
|
||||
export const TracklistEditor: React.FC = () => {
|
||||
const { rawText, errors, isValid, setRawText, setEntries, setErrors, setIsValid } = useTracklistStore()
|
||||
const { options } = useOptionsStore()
|
||||
const [isDragging, setIsDragging] = useState(false)
|
||||
|
||||
const validate = (text: string) => {
|
||||
const result = parseAndValidateTracklist(text, options.tracklist_format)
|
||||
setEntries(result.entries)
|
||||
setErrors(result.errors)
|
||||
setIsValid(result.isValid)
|
||||
}
|
||||
|
||||
const handleTextChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||
const text = event.target.value
|
||||
setRawText(text)
|
||||
validate(text)
|
||||
}
|
||||
|
||||
const validate = (text: string) => {
|
||||
const lines = text.split('\n').filter((line) => line.trim() !== '')
|
||||
const parsed = parseTracklist(lines)
|
||||
setEntries(parsed)
|
||||
|
||||
const validation = validateTracklist(parsed)
|
||||
setErrors(validation.errors)
|
||||
setIsValid(validation.isValid)
|
||||
}
|
||||
|
||||
const onDrop = useCallback(
|
||||
(acceptedFiles: File[]) => {
|
||||
if (acceptedFiles.length === 0) return
|
||||
@@ -50,17 +49,14 @@ export const TracklistEditor: React.FC = () => {
|
||||
multiple: false,
|
||||
})
|
||||
|
||||
// Initial validation on mount
|
||||
// Re-validate when tracklist format changes
|
||||
useEffect(() => {
|
||||
if (rawText) {
|
||||
validate(rawText)
|
||||
}
|
||||
}, [])
|
||||
}, [options.tracklist_format])
|
||||
|
||||
const getLineClassName = (lineIndex: number): string => {
|
||||
const hasError = errors.some((e) => e.line === lineIndex + 1)
|
||||
return hasError ? 'error-line' : ''
|
||||
}
|
||||
const lineCount = rawText.split('\n').filter(line => line.trim() !== '').length
|
||||
|
||||
return (
|
||||
<Paper
|
||||
@@ -79,9 +75,12 @@ export const TracklistEditor: React.FC = () => {
|
||||
<Typography variant="subtitle1" sx={{ mb: 2 }}>
|
||||
Tracklist
|
||||
<Typography variant="caption" color="text.secondary" sx={{ ml: 2 }}>
|
||||
{rawText ? `${rawText.split('\n').filter((l) => l.trim()).length} tracks` : 'No tracks yet'}
|
||||
{lineCount} track(s)
|
||||
{isValid ? ' ✅' : errors.length > 0 ? ` ⚠️ ${errors.length} error(s)` : ''}
|
||||
</Typography>
|
||||
<Typography variant="caption" color="text.secondary" sx={{ ml: 2 }}>
|
||||
Format: {options.tracklist_format}
|
||||
</Typography>
|
||||
</Typography>
|
||||
|
||||
<Box sx={{ display: 'flex', gap: 2 }}>
|
||||
@@ -112,7 +111,7 @@ export const TracklistEditor: React.FC = () => {
|
||||
maxRows={20}
|
||||
value={rawText}
|
||||
onChange={handleTextChange}
|
||||
placeholder={`Enter your tracklist here...\n\nExample:\n00:00 Intro\n01:30 Song One - Artist A\n04:20-06:45 Another Song - Artist B`}
|
||||
placeholder={`Enter your tracklist here...\n\nExample (format: ${options.tracklist_format}):\n00:00 Intro\n01:30 Song One - Artist A\n04:20-06:45 Another Song - Artist B`}
|
||||
variant="outlined"
|
||||
sx={{
|
||||
'& .MuiInputBase-root': {
|
||||
@@ -137,4 +136,4 @@ export const TracklistEditor: React.FC = () => {
|
||||
)}
|
||||
</Paper>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user