Merge pull request #39 from joelmathewthomas/client/zipdownload
Client/zipdownload
This commit is contained in:
@@ -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"
|
||||||
|
|||||||
@@ -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...");
|
||||||
|
|||||||
@@ -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');
|
||||||
@@ -73,28 +95,59 @@ function ResultsPage() {
|
|||||||
<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>
|
||||||
|
<Box sx={{ width: '100%', mt: 2, mb: 2 }}>
|
||||||
|
<Typography variant="body2" color="textSecondary" sx={{ mb: 1 }}>
|
||||||
|
{mediaFile.name}
|
||||||
</Typography>
|
</Typography>
|
||||||
{audioClass === "Music" ? (
|
|
||||||
audioRefs.map((ref, index) => (
|
|
||||||
<Box key={index} sx={{ width: '100%', mt: 2 }}>
|
|
||||||
<audio
|
<audio
|
||||||
ref={ref}
|
ref={mediaFileRef}
|
||||||
src={mediaFile.url}
|
src={mediaFile.url}
|
||||||
style={{ width: '100%' }}
|
style={{ width: '100%', borderRadius: '8px', boxShadow: '0 2px 10px rgba(0,0,0,0.2)' }}
|
||||||
controls
|
controls
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
))
|
{audioClass === "Music" ? (
|
||||||
) : (
|
<>
|
||||||
<Box sx={{ width: '100%', mt: 2 }}>
|
<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 }}>
|
||||||
|
<Typography variant="body2" color="textSecondary" sx={{ mb: 1 }}>
|
||||||
|
{file.name}
|
||||||
|
</Typography>
|
||||||
|
<audio
|
||||||
|
ref={audioRefs[index]}
|
||||||
|
src={file.url}
|
||||||
|
style={{ width: '100%', borderRadius: '8px', boxShadow: '0 2px 10px rgba(0,0,0,0.2)' }}
|
||||||
|
controls
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<Box sx={{ width: '100%', mt: 2 }}>
|
||||||
|
<Typography variant="h6" color="textPrimary" sx={{ mb: 1 }}>
|
||||||
|
Processed File
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
<Box sx={{ width: '100%', mt: 2 }}>
|
||||||
|
<Typography variant="body2" color="textSecondary" sx={{ mb: 1 }}>
|
||||||
|
{mediaFile?.name}
|
||||||
|
</Typography>
|
||||||
<audio
|
<audio
|
||||||
ref={audioRefs[0]}
|
ref={audioRefs[0]}
|
||||||
src={mediaFile.url}
|
src={downloadedFileURL}
|
||||||
style={{ width: '100%' }}
|
style={{ width: '100%', borderRadius: '8px', boxShadow: '0 2px 10px rgba(0,0,0,0.2)' }}
|
||||||
controls
|
controls
|
||||||
/>
|
/>
|
||||||
</Box>
|
</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>
|
||||||
|
|||||||
@@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user