Files
convert-ui/lib/utils/fileUtils.ts
Sebastian Krüger 67a1c47396 feat: add batch conversion support with multi-file upload and ZIP download
Major improvements:
- Updated FileUpload component to support multiple file selection
  - Added drag-and-drop for multiple files
  - Individual file removal
  - "Add More Files" button when files are selected
- Modified FileConverter to handle batch conversions
  - Sequential conversion of multiple files
  - Progress tracking for each file individually
  - All files share same output format and settings
- Added batch download functionality
  - Single file: direct download
  - Multiple files: ZIP archive download
  - Uses jszip library for ZIP creation
- Enhanced UI/UX
  - Show count of selected files in convert button
  - Display all conversion jobs with individual previews
  - "Download All" button for completed conversions
  - Conversion status messages show success/failure counts

Dependencies added:
- jszip@3.10.1 for ZIP file creation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-17 13:13:52 +01:00

115 lines
3.1 KiB
TypeScript

/**
* Format file size in human-readable format
*/
export function formatFileSize(bytes: number): string {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return `${Math.round(bytes / Math.pow(k, i) * 100) / 100} ${sizes[i]}`;
}
/**
* Validate file size (max 500MB for browser processing)
*/
export function validateFileSize(file: File, maxSizeMB: number = 500): boolean {
const maxBytes = maxSizeMB * 1024 * 1024;
return file.size <= maxBytes;
}
/**
* Get file extension from filename
*/
export function getFileExtension(filename: string): string {
const lastDot = filename.lastIndexOf('.');
return lastDot === -1 ? '' : filename.substring(lastDot + 1).toLowerCase();
}
/**
* Get filename without extension
*/
export function getFilenameWithoutExtension(filename: string): string {
const lastDot = filename.lastIndexOf('.');
return lastDot === -1 ? filename : filename.substring(0, lastDot);
}
/**
* Generate output filename
*/
export function generateOutputFilename(inputFilename: string, outputExtension: string): string {
const basename = getFilenameWithoutExtension(inputFilename);
return `${basename}.${outputExtension}`;
}
/**
* Download blob as file
*/
export function downloadBlob(blob: Blob, filename: string): void {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
/**
* Read file as ArrayBuffer
*/
export async function readFileAsArrayBuffer(file: File): Promise<ArrayBuffer> {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result as ArrayBuffer);
reader.onerror = () => reject(reader.error);
reader.readAsArrayBuffer(file);
});
}
/**
* Read file as Data URL
*/
export async function readFileAsDataURL(file: File): Promise<string> {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result as string);
reader.onerror = () => reject(reader.error);
reader.readAsDataURL(file);
});
}
/**
* Validate file type against allowed MIME types
*/
export function validateFileType(file: File, allowedTypes: string[]): boolean {
return allowedTypes.some((type) => {
if (type.endsWith('/*')) {
const category = type.split('/')[0];
return file.type.startsWith(`${category}/`);
}
return file.type === type;
});
}
/**
* Download multiple blobs as a ZIP file
*/
export async function downloadBlobsAsZip(files: Array<{ blob: Blob; filename: string }>, zipFilename: string): Promise<void> {
const JSZip = (await import('jszip')).default;
const zip = new JSZip();
// Add all files to ZIP
files.forEach(({ blob, filename }) => {
zip.file(filename, blob);
});
// Generate ZIP blob
const zipBlob = await zip.generateAsync({ type: 'blob' });
// Download ZIP
downloadBlob(zipBlob, zipFilename);
}