Upload de arquivos
Transforme um arquivo local em URL pública que o FFHub consegue ler.
Os workers do FFHub rodam na nuvem e só aceitam URLs públicas como entrada. Se o seu arquivo está no laptop, no celular ou em um bucket privado, faz o upload pro FFHub Storage primeiro pra pegar uma URL pública e usa ela no comando ffmpeg.
Como funciona o upload
São dois passos, e o arquivo nunca toca no nosso servidor. O cliente pega uma URL assinada de uso único e dá PUT direto no R2.
- Assina.
POST /v1/uploads/signdevolve uma URL pré-assinada válida por 15 minutos. - PUT. Sobe os bytes nessa URL com
curl,fetchou qualquer cliente HTTP.
Com isso dá pra subir arquivos de até 5 GB sem o nosso servidor estar no caminho dos dados.
Passo 1 — Pega uma URL assinada
curl -X POST https://api.ffhub.io/v1/uploads/sign \
-H "Authorization: Bearer $FFHUB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"filename": "input.mp4",
"size": 12345678,
"content_type": "video/mp4"
}'
Resposta:
{
"upload_url": "https://...r2.cloudflarestorage.com/...?X-Amz-Signature=...",
"public_url": "https://storage.ffhub.io/tmp/uploads/<user>/<rand>.mp4",
"key": "tmp/uploads/<user>/<rand>.mp4",
"content_type": "video/mp4",
"expires_at": "2026-05-12T05:30:00Z"
}
Passo 2 — Sobe o arquivo
curl -X PUT "$UPLOAD_URL" \
-H "Content-Type: video/mp4" \
--data-binary "@./input.mp4"
O header Content-Type tem que bater exatamente com o content_type que você mandou no passo 1 — senão o R2 rejeita a assinatura.
Quando o PUT retornar 200/204, a public_url do passo 1 já está pronta pra ler.
Exemplo completo
FILE=./input.mp4
SIZE=$(stat -f%z "$FILE" 2>/dev/null || stat -c%s "$FILE")
# 1. Assina
SIGNED=$(curl -s -X POST https://api.ffhub.io/v1/uploads/sign \
-H "Authorization: Bearer $FFHUB_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"filename\":\"input.mp4\",\"size\":$SIZE,\"content_type\":\"video/mp4\"}")
UPLOAD_URL=$(echo "$SIGNED" | jq -r '.upload_url')
PUBLIC_URL=$(echo "$SIGNED" | jq -r '.public_url')
# 2. PUT direto no R2
curl -X PUT "$UPLOAD_URL" \
-H "Content-Type: video/mp4" \
--data-binary "@$FILE"
# 3. Cria a tarefa usando a public_url como entrada
curl -X POST https://api.ffhub.io/v1/tasks \
-H "Authorization: Bearer $FFHUB_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"command\":\"-i $PUBLIC_URL -c:v libx264 -crf 28 output.mp4\"}"
A CLI faz essa dança toda automaticamente — veja CLI.
Limites
- Tamanho máximo: 5 GB por upload (limite do PUT único do R2)
- Validade da URL assinada: 15 minutos a partir de
expires_at; se passar disso, assina de novo - Validade do arquivo: 7 dias, depois o R2 apaga
Se precisar guardar por mais de 7 dias, copia pro seu próprio bucket assim que a tarefa terminar.
Já tem uma URL pública?
Pula esse fluxo inteiro. A API de tarefas aceita qualquer URL pública como entrada -i:
curl -X POST https://api.ffhub.io/v1/tasks \
-H "Authorization: Bearer $FFHUB_API_KEY" \
-H "Content-Type: application/json" \
-d '{"command":"-i https://example.com/clip.mp4 -c:v libx264 output.mp4"}'
Seu S3, seu CDN, nosso storage — pro módulo de tarefas tanto faz onde os bytes moram.