veza/apps/web/src/services/uploadService.ts

79 lines
2.4 KiB
TypeScript
Raw Normal View History

import { apiClient } from '@/services/api/client';
import { logger } from '@/utils/logger';
const CHUNK_SIZE = 1024 * 1024 * 2; // 2MB chunks
export interface UploadMetadata {
title: string;
artist?: string;
album?: string;
genre?: string;
}
export const uploadService = {
/**
* Effectue un upload partitionné (chunked) d'un fichier audio
*/
uploadTrack: async (file: File, metadata: UploadMetadata, onProgress?: (progress: number) => void) => {
const totalChunks = Math.ceil(file.size / CHUNK_SIZE);
// 1. Initier l'upload
const initiateResponse = await apiClient.post<{ upload_id: string }>('/tracks/initiate', {
filename: file.name,
total_chunks: totalChunks,
file_size: file.size,
title: metadata.title,
artist: metadata.artist,
album: metadata.album,
genre: metadata.genre,
});
const { upload_id } = initiateResponse.data;
logger.info(`[UPLOAD] Upload initiated with ID: ${upload_id}`, { filename: file.name, totalChunks });
// 2. Envoyer les morceaux (chunks)
for (let i = 0; i < totalChunks; i++) {
const start = i * CHUNK_SIZE;
const end = Math.min(start + CHUNK_SIZE, file.size);
const chunk = file.slice(start, end);
const formData = new FormData();
formData.append('chunk', chunk);
formData.append('index', i.toString());
formData.append('upload_id', upload_id);
try {
await apiClient.post('/tracks/chunk', formData, {
// Utiliser le timeout long pour les uploads
timeout: 300000,
// Pas besoin de logger chaque chunk en détail (trop verbeux)
_enableLogging: false,
} as any);
const progress = ((i + 1) / totalChunks) * 100;
if (onProgress) onProgress(progress);
} catch (error) {
logger.error(`[UPLOAD] Failed to upload chunk ${i} for ${upload_id}`, { error });
throw error;
}
}
// 3. Compléter l'upload
const completeResponse = await apiClient.post<{ track_id: string }>('/tracks/complete', {
upload_id
});
logger.info(`[UPLOAD] Upload completed. Track ID: ${completeResponse.data.track_id}`);
return completeResponse.data;
},
/**
* Récupère le statut d'une track en cours de traitement
*/
getTrackStatus: async (trackId: string) => {
const response = await apiClient.get<{ status: string; progress: number }>(`/tracks/${trackId}/status`);
return response.data;
},
};