Aller au contenu principal

Uploads reprenables avec un client TUS

Un client TUS éprouvé (tus-js-client, tus-py-client) sur l'API Videas, pour des uploads qui reprennent — y compris depuis le navigateur, sans clé API.

Le helper uploadFile du SDK est la voie facile, mais il ne reprend pas entre appels (un upload interrompu repart du premier chunk). Quand il vous faut une reprise robuste — réseau instable, fichiers de plusieurs Go, uploads qui survivent à un rechargement de page —, pilotez le transfert avec un client TUS éprouvé. Voici un court tuto, pour le navigateur et pour le serveur.

La clé à comprendre : deux niveaux d’auth

Le flux d’upload Videas a deux étapes avec des sécurités différentes :

Étape Endpoint Clé API requise ?
1. Créer la session POST /upload/ (Write Assets) Oui — clé secrète sk_ Serveur uniquement
2. Transférer les octets PATCH/HEAD sur la Location renvoyée Non — la Location est une URL-capacité secrète Serveur ou navigateur

La Location renvoyée est donc une URL d’upload secrète et à usage unique : quiconque la détient peut envoyer les octets, sans clé API. C’est ce qui rend possibles des uploads navigateur sûrs : votre serveur crée la session, le navigateur ne voit jamais que l’URL-capacité.

Uploads depuis le navigateur (pattern recommandé)

Ne mettez jamais votre clé sk_ dans le navigateur. À la place :

1. Votre serveur crée la session (il détient la clé) et renvoie la Location. Voir Envoyer avec l’API REST → étape 1 ; avec le SDK c’est videas.upload.createSession(...). Exposez un petit endpoint :

// serveur — POST /api/upload-session { filename, size }
app.post('/api/upload-session', async (req, res) => {
  const created = await videas.upload.createSession({
    headers: {
      'Tus-Resumable': '1.0.0',
      'Upload-Length': String(req.body.size),
      // paires clé <base64(valeur)> ; filename + workspace_uid sont requis
      'Upload-Metadata': `filename ${btoa(req.body.filename)},workspace_uid ${btoa('ws_123')}`,
    },
  })
  res.json({ location: created.location }) // l'URL-capacité — sûre pour le navigateur
})

2. Le navigateur transfère vers cette URL avec tus-js-client — par chunks, reprenable, sans clé :

<script type="module">
  import * as tus from 'https://cdn.jsdelivr.net/npm/tus-js-client@4/+esm'

  const file = input.files[0]
  const { location } = await (await fetch('/api/upload-session', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ filename: file.name, size: file.size }),
  })).json()

  const upload = new tus.Upload(file, {
    uploadUrl: location,            // reprendre une session déjà créée
    chunkSize: 32 * 1024 * 1024,    // ≤ 50 Mio (limite serveur par chunk)
    retryDelays: [0, 3000, 10000],  // réessais automatiques avec back-off
    onProgress: (sent, total) => console.log(`${Math.round((sent / total) * 100)} %`),
    onSuccess: () => console.log('terminé'),
    onError: (err) => console.error(err),
  })
  // Reprendre si ce fichier a déjà été partiellement envoyé, sinon démarrer.
  upload.findPreviousUploads().then((prev) => {
    if (prev.length) upload.resumeFromPreviousUpload(prev[0])
    upload.start()
  })
</script>

tus-js-client fait un HEAD sur la Location pour connaître l’offset courant, puis PATCH uniquement les octets manquants — une coupure (ou un rechargement de page) reprend au lieu de tout recommencer.

Uploads côté serveur (Node)

Côté serveur la clé est en sécurité : laissez tus-js-client faire les deux étapes — pointez-le sur l’endpoint de création avec votre clé et les métadonnées requises :

import * as tus from 'tus-js-client'
import { createReadStream, statSync } from 'node:fs'

const path = 'film.mp4'
const upload = new tus.Upload(createReadStream(path), {
  endpoint: 'https://api.videas.com/api/external/v1/upload/',
  headers: { Authorization: `Bearer ${process.env.VIDEAS_API_KEY}` },
  uploadSize: statSync(path).size,
  metadata: { filename: 'film.mp4', workspace_uid: 'ws_123', content_type: 'video/mp4' },
  chunkSize: 32 * 1024 * 1024,
  retryDelays: [0, 3000, 10000],
  onSuccess: () => console.log('terminé'),
})
upload.start()

Uploads côté serveur (Python)

Avec tus-py-client (pip install tuspy) :

import os
from tusclient import client

tus = client.TusClient(
    "https://api.videas.com/api/external/v1/upload/",
    headers={"Authorization": f"Bearer {os.environ['VIDEAS_API_KEY']}"},
)
uploader = tus.uploader(
    "film.mp4",
    chunk_size=32 * 1024 * 1024,  # ≤ 50 Mio
    metadata={"filename": "film.mp4", "workspace_uid": "ws_123"},
)
uploader.upload()  # reprenable : relancez pour continuer un upload interrompu

Après l’upload

Comme pour tout upload : vous obtenez un asset_uid, puis la vidéo est traitée de façon asynchrone — interrogez GET /assets/{uid}/ jusqu’à status: ready. Voir Comment fonctionnent les envois.

Lequel choisir ?

  • Simple, fichiers petits/moyens, côté serveur → le helper uploadFile du SDK (Envoyer avec le SDK).
  • Uploads navigateur → le serveur crée la session, le navigateur utilise tus-js-client avec uploadUrl (ci-dessus).
  • Reprise robuste / très gros fichiers → un client TUS (tus-js-client, tuspy).

Étapes suivantes