Upload multipart
Per i file video di grandi dimensioni (oltre 100 MB) ti consigliamo di usare l’upload multipart. Questo metodo divide il file in chunk più piccoli che vengono caricati in parallelo, offrendo maggiore affidabilità e prestazioni sui file grandi.
L’upload multipart è consigliato per file più grandi di 100 MB e supporta file fino a 60 GB.
Per un’implementazione più semplice, valuta la libreria Uppy, che gestisce automaticamente chunk, nuovi tentativi e tracciamento dell’avanzamento.
Panoramica
Il processo di upload multipart prevede quattro passaggi:
- Inizializzare — Crea un oggetto video e richiedi un upload multipart
- Ottenere URL firmati — Richiedi URL pre-firmati per ogni parte (in batch per efficienza)
- Caricare le parti — Carica ogni chunk sul suo URL firmato
- Completare — Segnala che tutte le parti sono state caricate
Inizializzare l’upload multipart
Crea un oggetto video inviando una richiesta PUT a /videos/upload con useMultipart: true.
CURL
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
}'Risposta
{
"videoId": "[VIDEO_ID]",
"title": "Your video title",
"multipartUpload": {
"uploadId": "[UPLOAD_ID]",
"key": "[S3_KEY]"
}
}Conserva i valori uploadId e key: ti servono per tutte le richieste successive.
Ottenere URL firmati per le parti
Prima di caricare le parti devi ottenere URL pre-firmati. Per efficienza, richiedi gli URL in batch invece che uno alla volta.
Richiesta in batch (consigliata)
Richiedi URL firmati per più parti in un colpo solo usando l’endpoint prepare-parts.
CURL
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}'Risposta
{
"parts": [
{ "partNumber": 1, "url": "[SIGNED_URL_FOR_PART_1]" },
{ "partNumber": 2, "url": "[SIGNED_URL_FOR_PART_2]" }
]
}Richiesta per una singola parte (fallback)
Se ti serve un URL per una parte specifica, puoi richiederlo singolarmente.
CURL
curl "https://app.ignitevideo.cloud/api/videos/upload/s3/multipart/[UPLOAD_ID]/[PART_NUMBER]?key=[S3_KEY]" \
-H "Authorization: Bearer YOUR_TOKEN"Caricare le parti
Dividi il file in chunk (consigliato: 5 MB - 100 MB per parte) e carica ogni chunk sul relativo URL firmato con una richiesta PUT.
Dimensione delle parti: l’upload multipart richiede una dimensione minima di 5 MB per parte (tranne l’ultima). Ti consigliamo chunk da 10 MB per un buon equilibrio tra parallelismo e overhead.
L’esempio qui sotto presuppone che tu abbia già ottenuto tutti gli URL firmati necessari. Per file con più di 100 parti devi recuperare gli URL in batch. Per gestire file grandi vedi anche l’Esempio completo qui sotto.
JavaScript / Node.js
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: devi raccogliere l’intestazione ETag dalla risposta di ogni caricamento di parte. Serve per completare l’upload multipart.
Completare l’upload multipart
Dopo che tutte le parti sono state caricate, invia una richiesta di completamento con l’elenco delle parti e i relativi ETag.
CURL
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\"" }
]
}'Per upload con più di 100 parti puoi usare fetchPartsFromStorage: true invece di passare l’array parts. Il server recupera automaticamente le informazioni sulle parti.
// 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 di codifica
Dopo il completamento dell’upload multipart il video viene sottoposto a codifica. Il processo può richiedere tempo a seconda delle dimensioni del video e della complessità della codifica.
Puoi controllare lo stato della codifica di un video chiamando l’endpoint /videos/[VIDEO_ID] come descritto nella sezione ottenere un video.
Esempio completo
Ecco un esempio JavaScript completo che implementa l’upload multipart con tracciamento dell’avanzamento:
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;
}Gestione degli errori
Se un upload fallisce, puoi riprovare le singole parti senza riavviare l’intero upload. Il valore uploadId resta valido per 24 ore.
Per le parti fallite:
- Richiedi un nuovo URL firmato per il numero di parte fallito
- Ricarica solo quella parte
- Prosegui con il passaggio di completamento quando tutte le parti sono caricate