Merge pull request #39 from joelmathewthomas/client/zipdownload

Client/zipdownload
This commit is contained in:
Joel Mathew Thomas
2025-03-18 17:52:13 +05:30
committed by GitHub
4 changed files with 154 additions and 26 deletions
+1
View File
@@ -16,6 +16,7 @@
"@mui/icons-material": "^5.15.10", "@mui/icons-material": "^5.15.10",
"@mui/material": "^5.15.10", "@mui/material": "^5.15.10",
"axios": "^1.8.3", "axios": "^1.8.3",
"jszip": "^3.10.1",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-router-dom": "^6.22.1" "react-router-dom": "^6.22.1"
+65 -3
View File
@@ -4,10 +4,11 @@ import { Typography, Container, Paper, Box, LinearProgress } from "@mui/material
import StepperComponent from "../components/StepperComponent"; import StepperComponent from "../components/StepperComponent";
import { useMediaContext } from "../contexts/MediaContext"; import { useMediaContext } from "../contexts/MediaContext";
import axios from "axios"; import axios from "axios";
import JSZip from "jszip";
function ProcessingPage() { function ProcessingPage() {
const navigate = useNavigate(); const navigate = useNavigate();
const { mediaFile, response } = useMediaContext(); const { mediaFile, response, setExtractedFiles, setDownloadedFileURL } = useMediaContext();
const [progress, setProgress] = useState(0); const [progress, setProgress] = useState(0);
const [statusText, setStatusText] = useState("Analyzing media..."); const [statusText, setStatusText] = useState("Analyzing media...");
@@ -39,6 +40,67 @@ function ProcessingPage() {
} }
}; };
const fetchZipDownload = async () => {
try {
setStatusText("Fetching Results...");
const res = await axios.get(`/api/download?file_uuid=${response.file_uuid}`, {
responseType: "blob",
});
if (res.status === 200) {
console.log("Download successful");
await handleDownload(res.data);
} else {
console.log("Failed to download the file");
}
} catch (error) {
console.error("Error fetching download:", error);
}
};
const fetchDownload = async () => {
try {
setStatusText("Fetching Results...");
const res = await axios.get(`/api/download?file_uuid=${response.file_uuid}`, {
responseType: "blob",
});
if (res.status === 200) {
console.log("Download successful");
const blob = new Blob([res.data], { type: "audio/wav" });
const fileURL = URL.createObjectURL(blob);
setDownloadedFileURL( fileURL );
setProgress(100);
} else {
console.log("Failed to download the file");
}
} catch (error) {
console.error("Error fetching download:", error);
}
};
const handleDownload = async (downloadData: Blob) => {
const zipBlob = new Blob([downloadData], { type: "application/zip" });
const zip = await JSZip.loadAsync(zipBlob);
const fileURLs = [];
for (const [filename, fileData] of Object.entries(zip.files)) {
if (!fileData.dir) {
const fileBlob = await fileData.async("blob");
const fileURL = URL.createObjectURL(fileBlob);
fileURLs.push({ name: filename, url: fileURL });
}
}
setExtractedFiles(fileURLs);
setProgress(100);
};
useEffect(() => { useEffect(() => {
if (!mediaFile) { if (!mediaFile) {
navigate("/upload"); navigate("/upload");
@@ -51,10 +113,10 @@ function ProcessingPage() {
processStep("/api/trim", () => { processStep("/api/trim", () => {
if (response.audio_class === "Music") { if (response.audio_class === "Music") {
processStep("/api/resample", () => { processStep("/api/resample", () => {
processStep("/api/separate", () => setProgress(100), 100, "Separating music into vocals, bass, drums and other..."); processStep("/api/separate", () => fetchZipDownload(), 90, "Separating music into vocals, bass, drums and other...");
}, 75, "Resampling audio to 44100Hz...", { sr: "44100" }); }, 75, "Resampling audio to 44100Hz...", { sr: "44100" });
} else { } else {
processStep("/api/noisereduce", () => setProgress(100), 100, "Reducing background noise from the audio..."); processStep("/api/noisereduce", () => fetchDownload(), 90, "Reducing background noise from the audio...");
} }
}, 50, "Trimming silent parts from the audio..."); }, 50, "Trimming silent parts from the audio...");
}, 25, "Normalizing audio frequency..."); }, 25, "Normalizing audio frequency...");
+80 -21
View File
@@ -21,12 +21,34 @@ import { useMediaContext } from '../contexts/MediaContext';
function ResultsPage() { function ResultsPage() {
const navigate = useNavigate(); const navigate = useNavigate();
const { mediaFile, response } = useMediaContext(); const { mediaFile, response, extractedFiles, downloadedFileURL } = useMediaContext();
console.log("Extracted files are", extractedFiles);
// const [isPlaying, setIsPlaying] = useState(false); // const [isPlaying, setIsPlaying] = useState(false);
const audioRefs = [useRef(null), useRef(null), useRef(null),useRef(null)]; const audioRefs = [useRef(null), useRef(null), useRef(null),useRef(null)];
const mediaFileRef = useRef(null);
const audioClass = response.audio_class const audioClass = response.audio_class
const isVideo = mediaFile?.type.includes('video'); const isVideo = mediaFile?.type.includes('video');
const handleDownloadAll = () => {
if (audioClass === 'Music') {
extractedFiles.forEach(({ name, url }) => {
const link = document.createElement('a');
link.href = url;
link.download = name;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
});
} else {
const link = document.createElement('a');
link.href = downloadedFileURL;
link.download = mediaFile?.name ?? 'downloaded_file';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
};
useEffect(() => { useEffect(() => {
if (!mediaFile) { if (!mediaFile) {
navigate('/upload'); navigate('/upload');
@@ -70,31 +92,62 @@ function ResultsPage() {
controls controls
/> />
) : ( ) : (
<Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center', p: 4, bgcolor: 'rgba(0, 0, 0, 0.04)', borderRadius: 2 }}> <Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center', p: 4, bgcolor: 'rgba(0, 0, 0, 0.04)', borderRadius: 2 }}>
<VolumeUpIcon color="primary" sx={{ fontSize: 80, mb: 2 }} /> <VolumeUpIcon color="primary" sx={{ fontSize: 80, mb: 2 }} />
<Typography variant="h6" gutterBottom> <Typography variant="h6" gutterBottom>
{mediaFile.name} (Processed) {mediaFile.name} (Original)
</Typography> </Typography>
<Box sx={{ width: '100%', mt: 2, mb: 2 }}>
<Typography variant="body2" color="textSecondary" sx={{ mb: 1 }}>
{mediaFile.name}
</Typography>
<audio
ref={mediaFileRef}
src={mediaFile.url}
style={{ width: '100%', borderRadius: '8px', boxShadow: '0 2px 10px rgba(0,0,0,0.2)' }}
controls
/>
</Box>
{audioClass === "Music" ? ( {audioClass === "Music" ? (
audioRefs.map((ref, index) => ( <>
<Box sx={{ width: '100%', mt: 2 }}>
<Typography variant="h6" color="textPrimary" sx={{ mb: 1 }}>
Processed Files
</Typography>
</Box>
{extractedFiles.map((file, index) => (
<Box key={index} sx={{ width: '100%', mt: 2 }}> <Box key={index} sx={{ width: '100%', mt: 2 }}>
<Typography variant="body2" color="textSecondary" sx={{ mb: 1 }}>
{file.name}
</Typography>
<audio <audio
ref={ref} ref={audioRefs[index]}
src={mediaFile.url} src={file.url}
style={{ width: '100%' }} style={{ width: '100%', borderRadius: '8px', boxShadow: '0 2px 10px rgba(0,0,0,0.2)' }}
controls controls
/> />
</Box> </Box>
)) ))}
</>
) : ( ) : (
<Box sx={{ width: '100%', mt: 2 }}> <>
<audio <Box sx={{ width: '100%', mt: 2 }}>
ref={audioRefs[0]} <Typography variant="h6" color="textPrimary" sx={{ mb: 1 }}>
src={mediaFile.url} Processed File
style={{ width: '100%' }} </Typography>
controls </Box>
/> <Box sx={{ width: '100%', mt: 2 }}>
</Box> <Typography variant="body2" color="textSecondary" sx={{ mb: 1 }}>
{mediaFile?.name}
</Typography>
<audio
ref={audioRefs[0]}
src={downloadedFileURL}
style={{ width: '100%', borderRadius: '8px', boxShadow: '0 2px 10px rgba(0,0,0,0.2)' }}
controls
/>
</Box>
</>
)} )}
</Box> </Box>
)} )}
@@ -108,7 +161,7 @@ function ResultsPage() {
File Details File Details
</Typography> </Typography>
<Typography variant="body2" color="textSecondary"> <Typography variant="body2" color="textSecondary">
<strong>Name:</strong> {mediaFile.name} (Processed) <strong>Name:</strong> {mediaFile.name}
</Typography> </Typography>
<Typography variant="body2" color="textSecondary"> <Typography variant="body2" color="textSecondary">
<strong>Type:</strong> {mediaFile.type} <strong>Type:</strong> {mediaFile.type}
@@ -118,13 +171,19 @@ function ResultsPage() {
</Grid> </Grid>
</Grid> </Grid>
<Box sx={{ mt: 4, display: 'flex', justifyContent: 'space-between' }}> <Box
sx={{
mt: 4,
display: 'flex',
justifyContent: 'space-between',
gap: 2,
flexWrap: 'wrap',
}}
>
<Button variant="outlined" color="primary" onClick={() => navigate('/upload')}> <Button variant="outlined" color="primary" onClick={() => navigate('/upload')}>
Process Another File Process Another File
</Button> </Button>
<Button variant="contained" color="primary" onClick={() => navigate('/')}> <Button variant="contained" color="primary" onClick={handleDownloadAll}>Download All Files</Button>
Back to Home
</Button>
</Box> </Box>
</Paper> </Paper>
</Container> </Container>
+7 -1
View File
@@ -5,6 +5,10 @@ interface MediaContextType {
setMediaFile: (file: { name: string; url: string; type: string }) => void; setMediaFile: (file: { name: string; url: string; type: string }) => void;
response: { file_uuid: string; sr: number; audio_class: string }; response: { file_uuid: string; sr: number; audio_class: string };
setResponse: (response: { file_uuid: string; sr: number; audio_class: string }) => void; setResponse: (response: { file_uuid: string; sr: number; audio_class: string }) => void;
extractedFiles: { name: string; url: string }[];
setExtractedFiles: (files: {name: string; url: string }[]) => void;
downloadedFileURL: string;
setDownloadedFileURL: ( file: string) => void;
} }
@@ -17,10 +21,12 @@ export const MediaProvider: React.FC<{ children: React.ReactNode }> = ({ childre
file_uuid: "", file_uuid: "",
sr: 0, sr: 0,
}); });
const [extractedFiles, setExtractedFiles] = useState<MediaContextType["extractedFiles"]>([]);
const [downloadedFileURL, setDownloadedFileURL] = useState<MediaContextType["downloadedFileURL"]>("");
return ( return (
<MediaContext.Provider value={{ mediaFile, setMediaFile, response, setResponse }}> <MediaContext.Provider value={{ mediaFile, setMediaFile, response, setResponse, extractedFiles, setExtractedFiles, downloadedFileURL, setDownloadedFileURL }}>
{children} {children}
</MediaContext.Provider> </MediaContext.Provider>
); );