Skip to Content
Referência APIVídeosUpload avançadoUpload multipart

Carregamento multipart

Para ficheiros de vídeo grandes (superiores a 100MB), recomendamos o carregamento multipart. Este método divide o teu ficheiro em partes mais pequenas que são carregadas em paralelo, o que melhora a fiabilidade e o desempenho para ficheiros grandes.

O carregamento multipart é recomendado para ficheiros maiores que 100MB e suporta ficheiros até 60GB.

Para uma implementação mais simples, considera a biblioteca Uppy, que trata da divisão em partes, novas tentativas e seguimento do progresso automaticamente.

Visão geral

O processo de carregamento multipart tem quatro passos:

  1. Inicializar — Criar um objeto de vídeo e pedir um carregamento multipart
  2. Obter URLs assinadas — Pedir URLs pré-assinadas para cada parte (em lotes para eficiência)
  3. Carregar partes — Carregar cada parte para o seu URL assinado
  4. Concluir — Indicar que todas as partes foram carregadas

Inicializar o carregamento multipart

Cria um objeto de vídeo enviando um pedido PUT para /videos/upload com useMultipart: true.

curl -X PUT https://app.ignitevideo.cloud/api/videos/upload \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "title": "Your video title", "mimeType": "video/mp4", "useMultipart": true }'

Resposta

{ "videoId": "[VIDEO_ID]", "title": "Your video title", "multipartUpload": { "uploadId": "[UPLOAD_ID]", "key": "[S3_KEY]" } }

Guarda os valores uploadId e key — vais precisar deles em todos os pedidos seguintes.

Obter URLs assinadas para as partes

Antes de carregares as partes, tens de obter URLs pré-assinadas. Por eficiência, pede URLs em lotes em vez de uma a uma.

Pedido em lote (recomendado)

Pede URLs assinadas para várias partes de uma vez com o endpoint prepare-parts.

curl -X POST "https://app.ignitevideo.cloud/api/videos/upload/s3/multipart/[UPLOAD_ID]/prepare-parts?key=[S3_KEY]" \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"startPart": 1, "endPart": 100}'

Resposta

{ "parts": [ { "partNumber": 1, "url": "[SIGNED_URL_FOR_PART_1]" }, { "partNumber": 2, "url": "[SIGNED_URL_FOR_PART_2]" } ] }

Pedido de uma única parte (alternativa)

Se precisares do URL de uma parte específica, podes pedi-lo individualmente.

curl "https://app.ignitevideo.cloud/api/videos/upload/s3/multipart/[UPLOAD_ID]/[PART_NUMBER]?key=[S3_KEY]" \ -H "Authorization: Bearer YOUR_TOKEN"

Carregar as partes

Divide o teu ficheiro em partes (recomendado: 5MB - 100MB por parte) e carrega cada parte para o URL assinado correspondente com um pedido PUT.

Tamanho das partes: O carregamento multipart exige um tamanho mínimo de 5MB por parte (exceto a última parte). Recomendamos partes de 10MB como equilíbrio entre paralelização e overhead.

O exemplo abaixo assume que já obtiveste todos os URLs assinados necessários. Para ficheiros com mais de 100 partes, tens de obter URLs em lotes. Vê o Exemplo completo abaixo para tratar ficheiros grandes.

const CHUNK_SIZE = 10 * 1024 * 1024; // 10MB chunks const file = yourVideoFile; // File object const totalParts = Math.ceil(file.size / CHUNK_SIZE); const uploadedParts = []; // Upload parts in parallel (limit concurrency to 5) const uploadPart = async (partNumber, signedUrl) => { const start = (partNumber - 1) * CHUNK_SIZE; const end = Math.min(start + CHUNK_SIZE, file.size); const chunk = file.slice(start, end); const response = await fetch(signedUrl, { method: 'PUT', body: chunk }); // Get the ETag from the response headers const etag = response.headers.get('ETag'); return { PartNumber: partNumber, ETag: etag }; }; // Upload all parts for (let i = 0; i < totalParts; i += 5) { const batch = []; for (let j = i; j < Math.min(i + 5, totalParts); j++) { const partNumber = j + 1; const signedUrl = partsData.parts.find(p => p.partNumber === partNumber)?.url; if (signedUrl) { batch.push(uploadPart(partNumber, signedUrl)); } } const results = await Promise.all(batch); uploadedParts.push(...results); }

Importante: Tens de recolher o cabeçalho ETag de cada resposta de carregamento de parte. São necessários para concluir o carregamento multipart.

Concluir o carregamento multipart

Depois de todas as partes estarem carregadas, envia um pedido de conclusão com a lista de partes e os respetivos ETags.

curl -X POST "https://app.ignitevideo.cloud/api/videos/upload/s3/multipart/[UPLOAD_ID]/complete?key=[S3_KEY]" \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "parts": [ { "PartNumber": 1, "ETag": "\"etag1\"" }, { "PartNumber": 2, "ETag": "\"etag2\"" } ] }'

Para carregamentos com mais de 100 partes, podes usar fetchPartsFromStorage: true em vez de passar o array de partes. O servidor obtém a informação das partes automaticamente.

// For large uploads with many parts const completeResponse = await fetch( `https://app.ignitevideo.cloud/api/videos/upload/s3/multipart/${uploadId}/complete?key=${encodeURIComponent(key)}`, { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_TOKEN', 'Content-Type': 'application/json' }, body: JSON.stringify({ fetchPartsFromStorage: true }) } );

Processo de codificação

Depois de o carregamento multipart estar concluído, o vídeo será codificado. Este processo pode demorar consoante o tamanho do vídeo e a complexidade da codificação.

Podes verificar o estado da codificação de um vídeo chamando o endpoint /videos/[VIDEO_ID] como descrito na secção obter vídeo.

Exemplo completo

Segue-se um exemplo completo em JavaScript que implementa o carregamento multipart com seguimento do progresso:

async function uploadLargeVideo(file, title, token) { const CHUNK_SIZE = 10 * 1024 * 1024; // 10MB const BATCH_SIZE = 100; const CONCURRENT_UPLOADS = 5; // Step 1: Initialize multipart upload const initResponse = await fetch('https://app.ignitevideo.cloud/api/videos/upload', { method: 'PUT', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ title, mimeType: file.type, useMultipart: true }) }); const { videoId, multipartUpload } = await initResponse.json(); const { uploadId, key } = multipartUpload; // Calculate total parts const totalParts = Math.ceil(file.size / CHUNK_SIZE); const uploadedParts = []; let uploadedBytes = 0; // Step 2 & 3: Get signed URLs and upload parts in batches for (let batchStart = 1; batchStart <= totalParts; batchStart += BATCH_SIZE) { const batchEnd = Math.min(batchStart + BATCH_SIZE - 1, totalParts); // Get signed URLs for this batch const urlsResponse = await fetch( `https://app.ignitevideo.cloud/api/videos/upload/s3/multipart/${uploadId}/prepare-parts?key=${encodeURIComponent(key)}`, { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ startPart: batchStart, endPart: batchEnd }) } ); const { parts } = await urlsResponse.json(); // Upload parts with concurrency limit for (let i = 0; i < parts.length; i += CONCURRENT_UPLOADS) { const chunk = parts.slice(i, i + CONCURRENT_UPLOADS); const uploads = chunk.map(async ({ partNumber, url }) => { const start = (partNumber - 1) * CHUNK_SIZE; const end = Math.min(start + CHUNK_SIZE, file.size); const blob = file.slice(start, end); const response = await fetch(url, { method: 'PUT', body: blob }); uploadedBytes += blob.size; const progress = (uploadedBytes / file.size) * 100; console.log(`Upload progress: ${progress.toFixed(1)}%`); return { PartNumber: partNumber, ETag: response.headers.get('ETag') }; }); const results = await Promise.all(uploads); uploadedParts.push(...results); } } // Step 4: Complete multipart upload uploadedParts.sort((a, b) => a.PartNumber - b.PartNumber); await fetch( `https://app.ignitevideo.cloud/api/videos/upload/s3/multipart/${uploadId}/complete?key=${encodeURIComponent(key)}`, { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ parts: uploadedParts }) } ); console.log(`Upload complete! Video ID: ${videoId}`); return videoId; }

Tratamento de erros

Se um carregamento falhar, podes repetir partes individuais sem recomeçar o carregamento inteiro. O uploadId mantém-se válido durante 24 horas.

Para partes falhadas:

  1. Pede um novo URL assinado para o número da parte que falhou
  2. Volta a carregar só essa parte
  3. Continua com o passo de conclusão quando todas as partes estiverem carregadas