Frontend and backend work together fine, complete workflow is implemented

This commit is contained in:
2026-08-01 17:04:03 +05:00
parent e87d8089bf
commit cd3ce0337b
13 changed files with 4499 additions and 86 deletions
+17 -1
View File
@@ -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>
)
}
}
+19 -20
View File
@@ -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>
)
}
}