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.

  1. Assina. POST /v1/uploads/sign devolve uma URL pré-assinada válida por 15 minutos.
  2. PUT. Sobe os bytes nessa URL com curl, fetch ou 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.

Upload de arquivos — FFHub Docs