Tutorial: repetir en bucle clips de audio con Transloadit y Uppy
Últimamente me he preguntado cuál de nuestros Robots merece un poco más de atención. Uno de nuestros verdaderos héroes anónimos, un caballo de batalla confiable que suele pasar desapercibido, es el Robot /audio/loop.
Hoy ponemos el foco en el Robot /audio/loop creando un sitio web que repite en bucle un clip de audio durante una duración determinada. Para ayudarnos con esto, también aprovecharemos la poderosa herramienta de subida de archivos Uppy.

Nuestras Assembly Instructions
Antes de entrar en los detalles de la creación del sitio web, repasemos las Assembly Instructions que usaremos para repetir nuestro audio en bucle.
{
"steps": {
"encode": {
"robot": "/audio/encode",
"use": ":original"
},
"loop": {
"robot": "/audio/loop",
"use": "encode",
"duration": "${fields.duration}"
},
"export": {
"robot": "/s3/store",
"use": "loop",
"credentials": "S3_CREDENTIALS",
"result": true
}
}
}
Primero codificamos el archivo de audio para estandarizar nuestro archivo de salida a MP3. Luego,
pasamos el archivo resultante al Robot /audio/loop. Cuando enviamos las
Assembly Instructions, el campo duration proporciona el número de segundos elegido por el usuario,
con 60 seleccionado inicialmente en el formulario. Por último, guardemos el resultado en un bucket
de S3 para poder presentarle este archivo al usuario. Si lo prefieres, también puedes usar uno de
los otros servicios de exportación con los que nos integramos.
Reemplaza S3_CREDENTIALS por el nombre de tus
credenciales de Template guardadas; no pegues secretos de S3 en el ejemplo.
Guarda estas Instructions como un Template y usa su ID en el JavaScript de abajo. El navegador envía la duración como un campo, así que no necesitamos una segunda copia de las Instructions en nuestro JavaScript. Nunca pongas un Auth Secret en el código del navegador. Antes de desplegar públicamente, usa firmas generadas en el servidor y valida la duración solicitada en tu servidor; la validación en el navegador por sí sola no autoriza el procesamiento.
El andamiaje HTML
Ahora que tenemos nuestras Assembly Instructions, comencemos con el andamiaje. Empezaremos agregando un poco de HTML para nuestro sitio web.
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link href="https://releases.transloadit.com/uppy/v3.3.1/uppy.min.css" rel="stylesheet" />
<title>Audio Looper</title>
</head>
<body>
<div class="banner">
<a href="https://uppy.io/"
><img src="https://transloadit.com/assets/images/artwork/logos-uppy-default-glyph.svg" alt="Uppy" width="48" height="48"
/></a>
<span id="cross">x</span>
<a href="https://transloadit.com/"
><img src="https://transloadit.com/assets/images/artwork/logos-transloadit-default-glyph.svg" alt="Transloadit" width="48" height="48"
/></a>
</div>
<h1 class="title">Audio Looper</h1>
<div class="input-container">
<label for="duration">Duration:</label>
<input type="number" id="duration" name="duration" min="1" max="300" step="1" value="60" required />
</div>
<div id="dashboard"></div>
<p class="label">Only accepts audio</p>
<div class="result-container">
<audio id="player" controls>
<source id="result" type="audio/mpeg" />
Your browser does not support the audio element.
</audio>
</div>
<p id="status" role="status"></p>
</body>
</html>
Lo que termina viéndose así:

Como puedes ver, es un sitio web bastante básico. Sin embargo, el estilo predeterminado es un poco difícil de digerir, así que agreguemos apenas una pizca de CSS para embellecerlo.
Dentro de dos etiquetas <style>, agrega el siguiente CSS:
.title {
text-align: center;
font-size: 2rem;
font-weight: 600;
margin-top: 2rem;
font-family: 'Courier New', Courier, monospace;
}
.label {
text-align: center;
font-size: 1rem;
font-weight: 100;
font-style: italic;
margin-top: 1rem;
font-family: 'Segoe UI', sans-serif;
}
.banner {
display: flex;
justify-content: center;
align-items: center;
gap: 1rem;
margin-top: 2rem;
}
.result-container {
display: flex;
justify-content: center;
margin-top: 2rem;
}
.input-container {
display: flex;
justify-content: center;
padding: 1rem;
font-family: 'Segoe UI', sans-serif;
}
input {
border: none;
border-bottom: 2px solid #bcbcbc;
text-align: end;
}
input:focus {
outline: 2px solid currentColor;
outline-offset: 2px;
}
#cross {
font-family: 'Courier New', monospace;
font-size: 2rem;
font-weight: 600;
}
#dashboard {
display: flex;
justify-content: center;
}
¡Ahora sí se ve mucho mejor!

El Dashboard de Uppy
Ahora que el HTML y el CSS están listos, podemos centrar nuestra atención en el dashboard de Uppy.
Después del HTML, agrega el siguiente JavaScript dentro de una etiqueta <script type="module">:
import {
Uppy,
Dashboard,
Transloadit,
} from 'https://releases.transloadit.com/uppy/v3.3.1/uppy.min.mjs'
const durationInput = document.getElementById('duration')
const status = document.getElementById('status')
const uppy = new Uppy({
restrictions: {
maxNumberOfFiles: 1,
allowedFileTypes: ['audio/*'],
},
onBeforeUpload: () => durationInput.reportValidity(),
})
.use(Dashboard, {
inline: true,
target: '#dashboard',
})
.use(Transloadit, {
waitForEncoding: true,
getAssemblyOptions: () => ({
params: {
auth: { key: 'YOUR_AUTH_KEY' },
template_id: 'YOUR_TEMPLATE_ID',
},
fields: { duration: durationInput.valueAsNumber },
}),
})
uppy.on('transloadit:complete', (assembly) => {
const url = assembly.results.export?.[0]?.ssl_url
if (typeof url !== 'string') {
status.textContent = 'No audio was returned. Please try again.'
return
}
const source = document.getElementById('result')
source.src = url
document.getElementById('player').load()
status.textContent = 'Your looped audio is ready.'
})
uppy.on('upload', () => {
status.textContent = 'Processing audio.'
})
uppy.on('error', () => {
status.textContent = 'Audio processing failed. Please try again.'
})
Aquí agregamos los plugins Dashboard y
Transloadit de Uppy, y establecemos el destino de nuestro componente
dashboard en el div #dashboard.
También pasamos el ID de nuestro Template al plugin de Transloadit y establecemos la
opción waitForEncoding en true, para poder analizar el archivo de resultado desde
el JSON de la Assembly, después de que nuestra Assembly haya terminado de codificar (en
lugar de cuando se completa nuestra subida).
La versión fijada de Uppy usa getAssemblyOptions para leer la duración actual cuando comienza la subida.
El input nativo requiere un número entero entre 1 y 300 segundos. El controlador de finalización lee
el archivo exportado, no el Step loop intermedio, y maneja un resultado ausente sin lanzar errores.
El resultado
Combina el HTML, el CSS y el script de módulo, configura tu propio Template y abre la página desde un servidor HTTP local. Las capturas de pantalla de arriba muestran el prototipo original; el código que ves aquí incluye el manejo actualizado del input y del resultado.
Cuando subas un archivo de audio y establezcas la duración, deberías ver el archivo de resultado en el elemento de audio de salida, con la duración establecida en el valor especificado.
Esperamos que esto te haya animado a echarle otro vistazo al Robot /audio/loop, así como al mejor gestor de subidas de archivos del mundo. Si quieres recibir avisos de futuras publicaciones del blog (¡y otras noticias tecnológicas relevantes!), suscríbete a nuestro boletín más abajo (English).
