added new zip download system

This commit is contained in:
averel10
2026-03-20 07:55:36 +01:00
parent c9080f3b3c
commit 815a509f4f
2 changed files with 73 additions and 22 deletions

View File

@@ -2,12 +2,46 @@ import { NextRequest, NextResponse } from 'next/server';
import { downloadFilteredEntries } from '@/app/actions/download-filtered-entries';
import JSZip from 'jszip';
import { join } from 'path';
import { readFile, existsSync } from 'fs';
import { readFile, existsSync, writeFileSync, mkdirSync, readdirSync, unlinkSync, statSync } from 'fs';
import { promisify } from 'util';
import { requireAdmin } from '@/lib/auth';
const readFileAsync = promisify(readFile);
// Clean up old ZIP files older than 24 hours
async function cleanupOldZips(downloadsDir: string, maxAgeHours: number = 24) {
try {
if (!existsSync(downloadsDir)) {
return;
}
const files = readdirSync(downloadsDir);
const now = Date.now();
const maxAgeMs = maxAgeHours * 60 * 60 * 1000;
for (const file of files) {
if (!file.startsWith('dataset-') || !file.endsWith('.zip')) {
continue;
}
const filePath = join(downloadsDir, file);
try {
const stats = statSync(filePath);
const fileAge = now - stats.mtimeMs;
if (fileAge > maxAgeMs) {
unlinkSync(filePath);
console.log(`Cleaned up old ZIP file: ${file} (age: ${(fileAge / (60 * 60 * 1000)).toFixed(1)} hours)`);
}
} catch (error) {
console.error(`Error cleaning up file ${file}:`, error);
}
}
} catch (error) {
console.error('Error during cleanup:', error);
}
}
interface FilterParams {
speakerId?: string;
modelName?: string;
@@ -84,16 +118,37 @@ export async function POST(request: NextRequest) {
// Generate ZIP blob
const zipBuffer = await zip.generateAsync({ type: 'nodebuffer' });
// Create response with ZIP file
const fileName = `dataset-${datasetId}-export-${new Date().toISOString().split('T')[0]}.zip`;
// Save ZIP to public folder
const downloadsDir = join(process.cwd(), 'public', 'downloads');
return new NextResponse(new Uint8Array(zipBuffer), {
status: 200,
headers: {
'Content-Type': 'application/zip',
'Content-Disposition': `attachment; filename="${fileName}"`,
'Content-Length': zipBuffer.length.toString(),
},
// Ensure downloads directory exists
try {
mkdirSync(downloadsDir, { recursive: true });
} catch (error) {
console.error('Error creating downloads directory:', error);
}
// Create filename with timestamp for uniqueness
const timestamp = Date.now();
const fileName = `dataset-${datasetId}-export-${new Date().toISOString().split('T')[0]}-${timestamp}.zip`;
const filePath = join(downloadsDir, fileName);
// Write ZIP file to disk
writeFileSync(filePath, zipBuffer);
console.log(`ZIP file saved to: ${filePath}`);
// Clean up old ZIP files in the background
cleanupOldZips(downloadsDir).catch(error => {
console.error('Cleanup failed:', error);
});
// Return download URL
const downloadUrl = `/downloads/${fileName}`;
return NextResponse.json({
success: true,
downloadUrl,
fileName,
});
} catch (error) {
console.error('Error creating ZIP:', error);

View File

@@ -24,21 +24,17 @@ export async function downloadFilteredEntriesAsZip(
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error || 'Failed to download ZIP');
throw new Error(errorData.error || 'Failed to prepare ZIP');
}
// Get the ZIP blob from response
const blob = await response.blob();
const data = await response.json();
// Trigger download
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `dataset-${datasetId}-export-${new Date().toISOString().split('T')[0]}.zip`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
if (!data.success || !data.downloadUrl) {
throw new Error('Invalid response from server');
}
// Redirect to the generated ZIP file
window.location.href = data.downloadUrl;
} catch (error) {
console.error('Error downloading ZIP:', error);
throw error;