Blog

Live engagementHow-toAPI

Reliez votre photobooth au grand écran

Votre photobooth fait déjà de belles photos. Avec l’API Engagement, chaque prise arrive quelques secondes plus tard sur le mur de polaroids, et l’invité scanne un QR code pour l’emporter. Les trois appels, et une recette pour Sparkbooth, pibooth, dslrBooth et tout photobooth avec un dossier de sortie.

The Wunderframe team 8 min read

Le photobooth est le coin le plus animé de la plupart des fêtes. Mais ce qu’il photographie reste en général dans la cabine : l’invité voit sa photo quelques secondes sur un petit écran, et les autres ne voient rien jusqu’à ce que le lien de la galerie arrive une semaine plus tard.

Si l’événement tourne avec Wunderframe, votre photobooth peut publier directement dans l’engagement de la soirée, le même que celui où les invités publient depuis leur téléphone. La photo s’affiche sur le mur de polaroids quelques secondes plus tard, et l’invité scanne un QR code pour l’emporter. Vous gardez votre photobooth, votre appareil photo et votre logiciel. Vous ajoutez quelques lignes de code.

Pourquoi les photos du photobooth ont leur place sur le grand écran

  • C’est instantané. Le tirage se révèle sur le mur pendant que l’invité pose encore les accessoires. C’est le moment où les gens lèvent les yeux.
  • Tout le monde le voit. Un seul photobooth devient un spectacle pour toute la salle, à côté des photos et des notes que les invités envoient depuis leur téléphone.
  • Les invités l’emportent. Chaque photo reçoit son propre lien à emporter : une page sur le téléphone de l’invité avec sa photo et les boutons Partager et Enregistrer. Pas d’application, pas d’adresse e-mail, pas de galerie à fouiller.
Un grand écran sombre intitulé « Shoot a polaroid » avec une rangée de photos instantanées inclinées – un coucher de soleil sur le port, les lumières d’une scène de conférence, un tram en ville, des confettis avec « Day 1! », des croquis d’atelier, une vue sur le lac et un latte – chacune avec une légende manuscrite, et un QR code dans le coin.

Le mur de polaroids. Une photo du photobooth y prend place à côté des photos que les invités envoient depuis leur téléphone.

Le déroulement : trois appels et une courte attente

D’abord, en tant que propriétaire (owner) du workspace, créez une clé d’API sous Settings → Integrations avec Live engagements (engagements:write). Gardez-la sur l’ordinateur du photobooth ou sur votre serveur, jamais dans une page web. GET /api/v1/engagements vous donne l’id de l’engagement, ses rooms avec leurs clés, et s’il demande un consentement (consent). Ensuite, pour chaque photo :

  1. Demander un upload. POST /api/v1/engagements/{id}/uploads avec kind, mime et la taille exacte en bytes. Vous recevez un upload_id et une upload_url signée.
  2. Envoyer le fichier. Envoyez les octets par PUT à upload_url, avec les headers indiqués dans la réponse, tout de suite : l’URL est de courte durée et ne sert qu’une fois.
  3. Publier. POST /api/v1/engagements/{id}/posts avec l’upload_id, un client_label comme Booth 1, la clé de la room si l’engagement a des salles, et "consent": true s’il demande un consentement. Envoyez un en-tête Idempotency-Key : le hash du fichier convient très bien.
  4. Attendre la copie. Interrogez GET /api/v1/engagements/{id}/posts/{post_id} toutes les deux secondes jusqu’à ce que share_ready soit true, puis affichez take_home_url en QR code.

Tout le déroulement en Node.js 18 ou plus récent, sans rien installer :

// send-shot.mjs
import { readFile } from 'node:fs/promises';
import { createHash } from 'node:crypto';

const API = 'https://www.wunderframe.com/api/v1';
const ENG = process.env.WUNDERFRAME_ENGAGEMENT; // the engagement id
const KEY = process.env.WUNDERFRAME_KEY;        // engagements:write

async function call(method, path, body, headers = {}) {
  const res = await fetch(API + path, { method, body: body && JSON.stringify(body),
    headers: { Authorization: `Bearer ${KEY}`, 'Content-Type': 'application/json', ...headers } });
  const data = await res.json();
  if (!res.ok) throw new Error(`${res.status} ${data.error.code}: ${data.error.message}`);
  return data;
}

/** Upload, post, wait for the copy. Returns the link for the QR code. */
export async function sendShot(bytes, { room, label = 'Booth 1', wait = true } = {}) {
  const hash = createHash('sha256').update(bytes).digest('hex');
  const up = await call('POST', `/engagements/${ENG}/uploads`,
    { kind: 'photo', mime: 'image/jpeg', bytes: bytes.length });
  const put = await fetch(up.upload_url, { method: up.method, headers: up.headers, body: bytes });
  if (!put.ok) throw new Error(`upload ${put.status}`);
  // consent: true only once the guest agreed on the booth's screen
  let post = await call('POST', `/engagements/${ENG}/posts`,
    { kind: 'photo', upload_id: up.upload_id, client_label: label, room, consent: true },
    { 'Idempotency-Key': hash });
  for (let i = 0; wait && i < 30 && post.take_home_url && !post.share_ready; i++) {
    await new Promise((r) => setTimeout(r, 2000));
    post = await call('GET', `/engagements/${ENG}/posts/${post.post_id}`);
  }
  return post.take_home_url;
}

// node send-shot.mjs shot.jpg
if (process.argv[2]) console.log(await sendShot(await readFile(process.argv[2])));

L’API s’occupe de plusieurs choses pour vous. La publication passe par la modération de l’engagement comme celle d’un invité : avec approval, elle attend la régie avant d’arriver sur les murs. Le lien à emporter est valable 24 heures, et chaque interrogation renvoie le même lien. Si quelqu’un scanne avant que la copie soit prête, la page attend simplement quelques secondes. Avec le plan gratuit, la copie partagée porte une petite marque Wunderframe dans un coin ; les murs affichent toujours la photo sans elle. Les mêmes quelques lignes en Python se trouvent dans la documentation.

Une recette pour votre photobooth

Les logiciels de photobooth se rangent en trois familles : certains envoient vers un serveur que vous indiquez, d’autres lancent un plugin ou un script après chaque photo, d’autres encore ne font qu’écrire des fichiers dans un dossier. Il existe une porte d’entrée pour les trois.

Sparkbooth : un petit relais

Le Custom Upload de Sparkbooth envoie chaque photo en POST multipart vers une Service URL de votre choix, avec les champs media, username, password, name, email et message. Il attend en retour {"status":true,"url":"…"} et affiche cette url en QR code sur son écran de partage. Un relais reçoit donc l’upload, appelle l’API Engagement et répond avec le lien à emporter :

// relay.mjs, next to send-shot.mjs
import { createServer } from 'node:http';
import { sendShot } from './send-shot.mjs';

createServer(async (req, res) => {
  const form = await new Request('http://relay' + req.url,
    { method: 'POST', headers: req.headers, body: req, duplex: 'half' }).formData();
  if (form.get('password') !== process.env.RELAY_PASSWORD) return res.writeHead(401).end();
  try {
    const bytes = Buffer.from(await form.get('media').arrayBuffer());
    const url = await sendShot(bytes, { wait: false }); // the page waits for the copy itself
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ status: true, url }));
  } catch (err) {
    res.writeHead(502).end(); // and keep the bytes in a queue to retry
  }
}).listen(8080);

Répondez vite : Sparkbooth attend le relais, et la page à emporter attend la copie d’elle-même. La clé ne se trouve que dans le relais, et celui-ci ignore email, dont Wunderframe n’a pas besoin.

pibooth : un plugin de quelques lignes

pibooth, le photobooth pour Raspberry Pi, exécute des plugins Python sur des hooks. Après le traitement, la photo finale est app.previous_picture_file. Un plugin d’upload renseigne app.previous_picture_url, comme le fait pibooth-google-photo, et pibooth-qrcode l’affiche lorsque son prefix_url vaut {url}. Une esquisse, où post_shot est la version Python des trois appels tirée de la documentation :

import pibooth
from booth import post_shot  # upload, post, wait: returns take_home_url

@pibooth.hookimpl(tryfirst=True)  # set the URL before the QR plugin reads it
def state_processing_exit(cfg, app, win):
    try:
        app.previous_picture_url = post_shot(app.previous_picture_file)
    except Exception:
        app.previous_picture_url = None
        queue_for_later(app.previous_picture_file)  # retry when back online

dslrBooth et LumaBooth pour Windows : un trigger

Ces photobooths ont des Triggers : lors d’événements comme processing_start, qui transmet le final_file, ou session_end, ils appellent une URL de webhook ou lancent une application. Pointez-en un vers send-shot.mjs ou vers un petit webhook local, et le fichier final part sur le mur. Leurs propres QR codes mènent à l’hébergement de Lumasoft : affichez donc vous-même le QR code à emporter, comme décrit plus bas.

PhotoboothProject et photobooth-app : une commande ou un plugin

Le PhotoboothProject, basé sur le web, lance après chaque photo une commande où %s est le nom du fichier : node send-shot.mjs %s suffit. photobooth-app accepte comme pibooth des plugins Python sur ses hooks, et son synchroniseur rclone peut aussi copier les photos dans un dossier que la recette suivante surveille.

Tout autre photobooth : surveiller le dossier de sortie

Les applications fermées comme LumaBooth sur iPad, Darkroom ou Breeze écrivent leurs photos finales dans un dossier de sortie. Surveillez ce dossier et envoyez chaque nouveau fichier : avec inotifywait ou rclone sous Linux, avec Hazel sous macOS. Attendez que le fichier soit entièrement écrit, sinon vous envoyez une demi-photo. Sous Linux, close_write et moved_to ne se déclenchent qu’à ce moment-là :

inotifywait -m -e close_write -e moved_to --format '%w%f' /srv/booth/out |
while read -r file; do
  node send-shot.mjs "$file" || cp "$file" /srv/booth/queue/
done

Afficher le QR code

Sur le photobooth, quand il le permet. Sparkbooth affiche l’url que votre relais renvoie, et pibooth-qrcode affiche app.previous_picture_url. L’invité scanne au moment même où il voit sa photo, c’est-à-dire quand il la veut.

À côté du photobooth, quand il ne le permet pas. Si le photobooth n’affiche que son propre code, laissez votre script afficher le QR code à emporter : une fenêtre de navigateur en plein écran sur un second moniteur du photobooth, ou un petit écran juste à côté, toujours avec le lien le plus récent. Les grands écrans près du mur de polaroids font alors ce qu’ils font de mieux : montrer chaque photo dès son arrivée, avec le QR code de l’engagement, pour que les invités sans photobooth puissent publier depuis leur téléphone.

Laissez un code à emporter près du photobooth et affiché une vingtaine de secondes. Il ouvre la photo d’une seule personne, il n’a donc pas sa place sur l’écran de scène, où toute la salle peut le scanner.

Le photobooth prend la photo. Le mur la montre à la salle. Le QR code l’envoie à la maison.

Le déroulement en une phrase

Liste de contrôle pour la protection des données et la fiabilité

  • Demander, puis publier. Si l’engagement demande un consentement, affichez son consent.text sur l’écran d’accueil du photobooth et n’envoyez "consent": true qu’après l’accord de l’invité. Placez au photobooth une mention bien visible indiquant que ses photos apparaissent sur les écrans.
  • Modérer avant d’afficher. Réglez l’engagement sur approval si une personne doit voir chaque photo avant la salle. Une publication refusée perd son lien à emporter.
  • Collecter le moins possible. Wunderframe n’a besoin ni d’adresse e-mail ni de nom. client_label désigne le photobooth, pas la personne. La durée de conservation de l’engagement s’applique aux photos du photobooth comme à toutes les autres.
  • Mettre en file d’attente hors ligne. Gardez chaque photo sur le photobooth et envoyez-la dès que le réseau revient. Le photobooth continue de photographier.
  • Réessayer sans risque. Réessayez une publication avec le même upload_id et la même Idempotency-Key : vous recevez la première publication au lieu d’une seconde. Une fois publié, réessayez la publication, jamais l’upload.
  • Surveiller l’URL d’upload. Elle est de courte durée et ne sert qu’une fois. Si le PUT échoue ou arrive trop tard, demandez un nouvel upload : rien n’a encore été publié.
  • Vérifier avant que l’invité se présente. Lisez l’engagement : si son state est closed, les publications sont refusées avec 423. Que le photobooth le dise, plutôt que de prendre une photo qui ne pourra pas s’afficher.
  • Protéger la clé. Elle peut publier dans chaque engagement de votre workspace. Gardez-la sur l’ordinateur du photobooth ou dans le relais, et révoquez-la sous Settings → Integrations si elle fuite.

Reliez votre photobooth avant le prochain événement

Chaque champ, chaque erreur et chaque limite se trouvent dans The Engagement API, avec l’exemple du photobooth en curl, Node.js et Python, et dans la référence de l’API. Le fonctionnement du mur de polaroids est décrit dans Du QR code au mur de polaroids, et la façon dont photobooth et écrans travaillent ensemble dans Louer un photobooth ou un photobooth numérique sur vos écrans ? Vous exploitez des photobooths à titre professionnel ? Voyez Wunderframe pour les photographes. Les plans sont sur la page Tarifs. Commencez gratuitement, créez un engagement et une clé d’API, et envoyez une photo de test sur le mur.

Live engagement, How-to

A guest photo wall for your wedding, no app needed

Guests take the best photos of a wedding, and the couple usually sees them weeks later. A photo wall puts them on the big screen during the party. How to set one up, what makes guests use it, and what to decide about privacy first.

The Wunderframe team 3 min read

Event production, Live presenters

Live speakers without surprises: a playbook for event managers

Rehearsals, the backstage link, a network you control, operators for every room and a Q&A that knows who picks the questions. What to prepare with your speakers before the day, and how the day itself runs.

The Wunderframe team 13 min read