J'ai construit la stack technique de ⌘+P : The App Podcast comme un développeur d'apps construit une app — pas comme un podcaster bricole un Spotify for Podcasters. Voici ce que ça donne quand on traite le RSS comme un produit.
Les premiers épisodes de ⌘+P ont été enregistrés chez Podspace à Paris — une vraie cabine, des vrais micros, un vrai ingé son qui ne fait pas semblant de comprendre quand tu lui parles de bus AES vs sortie monitoring. Le montage, lui, je le fais sur mon Mac dans Final Cut Pro, parce qu'on ne va pas se mentir : un développeur Apple qui monterait son podcast sur Premiere, ce serait comme un chef italien qui fait sa carbonara à la crème. Ça se sent, et les gens te jugent (à raison).
Ce que j'ai sous-estimé, c'est qu'enregistrer et monter, c'est environ 20% du travail. Le reste, c'est la distribution. Et la distribution d'un podcast en 2026, c'est un terrain bien plus piégé qu'il n'y paraît.
Cet article est l'autopsie technique de la stack que j'ai construite pour ⌘+P : trois flux RSS différents, un CMS headless, un CDN custom, un encoder vidéo adaptatif, et une obsession assumée pour Apple Podcasts. Si tu envisages de lancer un podcast sérieux sans passer par Acast ou Spotify for Podcasters, c'est probablement la lecture la plus dense que tu trouveras sur le sujet francophone cette année.
Le pari : traiter le RSS comme un produit
La question qui m'a évité six mois d'errance : est-ce que je veux que mon podcast vive sur la plateforme de quelqu'un d'autre, ou est-ce que je veux qu'il vive chez moi ?
Spotify for Podcasters (anciennement Anchor) propose un deal apparemment imbattable : tu uploades ton .wav, ils te génèrent un flux RSS, ils gèrent l'hébergement audio, ils poussent vers Apple Podcasts. Gratuit. Le piège, évidemment, c'est que ton flux RSS leur appartient. Le jour où tu veux changer d'hébergeur, tu emportes ton archive mais tu perds tes statistiques, tes liens canoniques, et parfois ta légitimité auprès des annuaires qui t'ont indexé depuis le flux Anchor d'origine. Acast, c'est la même logique avec une UX plus pro et une facture mensuelle.
J'ai choisi l'inverse. Le flux RSS est un endpoint que je contrôle, sur mon domaine, généré par mon code, à partir de ma source de vérité. Apple, Spotify, Pocket Casts, Castro, Overcast — tout le monde vient s'abonner chez moi. Si demain Spotify devient hostile, je change deux lignes de XML, pas mon hébergeur.
Cette décision a une conséquence en cascade : si je gère le RSS, je dois aussi gérer tout ce qui va avec. Le CMS, le stockage des fichiers audio et vidéo, l'encoding, le CDN, les chapitres, les métadonnées Podcasting 2.0, les variantes par plateforme. C'est plus de travail. C'est aussi infiniment plus formateur, et la stack qui en sort est étonnamment légère.
La source de vérité : Hygraph
Le contenu vit dans Hygraph, un CMS headless GraphQL. J'ai un modèle PodcastEpisode qui porte tout ce que tu attends — saison, numéro d'épisode, invités, chapitres, URLs audio et vidéo, show notes en rich-text, dates, flags isPrivate et showOnHomepage. Les invités sont une entité séparée PodcastGuest avec sa propre bio rich-text et son linkedinUrl, parce qu'un même invité peut revenir, et que dupliquer une bio dans deux entrées différentes est le genre de péché qu'on regrette six mois plus tard. La vidéo, elle, vit sur une entité Video réutilisable que PodcastEpisode référence — j'y reviens, c'est devenu central.
Le site qui consomme tout ça, c'est du Next.js 16 App Router avec Turbopack et Tailwind v4, déployé sur Clever Cloud avec un push git → redeploy automatique. La couche GraphQL utilise Apollo Client. L'i18n passe par next-intl avec sept locales (en, fr, de, it, nl, ar-AE, ar-SA) et localePrefix: 'as-needed'. Détail qui a son importance : le show est francophone, donc même quand le visiteur arrive sur /de/podcast, le RSS force locales: ['fr', 'en'] côté Hygraph. Le RSS n'est pas multilingue, il est bilingue par essence — et Apple Podcasts s'attendrait à ce qu'il le soit, peu importe où tu cliques.
Le stockage : Clever Cloud Cellar derrière Cloudflare
Les fichiers média (audio, vidéo, covers) vivent sur Clever Cloud Cellar, leur stockage S3-compatible, derrière un CDN Cloudflare sur cdn2.clementsauvage.me. Ce choix n'est pas évident, alors je le justifie.
Mux est tentant pour tout faire — encoding, streaming, distribution. Sauf qu'à l'échelle d'un podcast vidéo qui peut peser 250 Mo par épisode, la facture Mux devient déraisonnable très vite si tu multiplies les téléchargements RSS. Cellar, c'est un prix prévisible au gigaoctet, du byte-range natif (vérifié, Range: bytes=0-1023 retourne bien un HTTP 206), et l'app est déjà déployée sur Clever Cloud — la latence inter-services est négligeable. Le byte-range est non négociable, parce que les clients podcasts ne téléchargent jamais un fichier d'un coup : ils streament progressivement, et ils s'attendent à pouvoir reprendre.
Mux reste utilisé, mais uniquement pour le streaming web : HLS adaptatif via playbackId, joué par mux-player-react côté navigateur sur la page épisode. La vidéo embarquée sur le site bénéficie d'un encoding ladder pro géré par Mux, et le master MP4 H.264 sur Cellar sert exclusivement la distribution RSS. Deux usages, deux fichiers, deux stratégies. C'est plus de stockage à payer, mais chaque fichier fait son métier sans compromis.
L'admin d'import : où le contexte vient en premier
J'ai un endpoint privé, un l'outil qui prend un .mp3 brut sorti de Final Cut, une cover JPEG, et qui produit un épisode draft dans Hygraph prêt à être validé.
La leçon UX qui m'a coûté une refonte : le contexte doit venir avant le contenu. Première version, j'avais les fichiers en haut et les champs Saison / Épisode / Type / Langue en bas. Logique côté formulaire. Catastrophique côté pipeline, parce que ces quatre champs déterminent le chemin d'upload sur Cellar (cmd-p-podcast/s{n}/episode-{m}/audio.wav). Si tu drop tes fichiers avant d'avoir choisi la saison, soit le serveur t'envoie chier, soit il devine et tu te retrouves avec un épisode 12 stocké dans le dossier de l'épisode 11. J'ai inversé : grille 2×2 contexte d'abord, drop zone ensuite. Le formulaire n'autorise plus l'upload tant que les quatre champs ne sont pas remplis. Plus jamais ce bug.
L'upload lui-même est du S3 multipart présigné côté navigateur : le serveur génère des URLs présignées par chunk de 64 Mo, le browser PUT directement sur Cellar, le serveur reçoit les ETags pour assembler le multipart à la fin. Un endpoint dédié configure le CORS du bucket avec ExposeHeaders: ETag parce que sans ça, le browser ne peut pas remonter les ETags et le complete échoue silencieusement. Détail qu'on ne trouve dans aucune doc S3 grand public.
Pour les teasers, j'ai une convention de nommage spécifique : un suffixe alphanumérique de 7 caractères tirés d'un alphabet de 55 (sans 0, 1, I, O, i, l, o pour éviter les confusions visuelles). La clé est régénérée à chaque passage en mode TEASER et partagée entre les trois fichiers d'un même teaser (audio/vidéo/cover). Ça permet de coexister plusieurs teasers pour la même saison/épisode sans écraser, et l'URL reste prononçable au téléphone. C'est trois lignes de code et ça t'évite d'engueuler ton invité parce que tu as overwrite son teaser avec un autre.
Le pipeline complet, après upload : Mux ingère la vidéo et génère un asset + playback ID + thumbnail à un timestamp choisi. AssemblyAI transcrit l'audio et génère des chapitres automatiques. Une preview édit-friendly s'affiche dans l'admin avec description courte, show notes, chapitres (titre / start / end). Tout est éditable avant l'écriture Hygraph. À la validation, on crée un PodcastEpisode en draft avec un episodeGuid UUID stable, l'asset Mux référencé, le transcript AssemblyAI, et les chapitres séparés du blob show-notes — l'UI du site et le <podcast:chapters> JSON les surfacent indépendamment, donc les fusionner serait une erreur d'architecture qu'on payerait à chaque update.
Le RSS : trois flux, trois stratégies
C'est ici que ça devient intéressant. Apple Podcasts est traité en priorité. C'est le flux principal, le seul qui sort en temps réel, le seul qui reçoit toutes les fonctionnalités Podcasting 2.0. Spotify et le reste passent en second.
Concrètement, j'ai trois endpoints :
/podcast/rss— flux principal, épisodes publiés immédiatement, full Podcasting 2.0/podcast/rss/late— même contenu avec un délai de 3 jours/podcast/rss/spotify— flux audio-only, délai de 3 jours, conformité Spotify stricte
Le délai de 3 jours est un choix éditorial assumé. Apple Podcasts reçoit l'épisode le mardi matin. Spotify et les annuaires secondaires le reçoivent le vendredi. Pendant ces 72 heures, l'audience qui vient d'Apple Podcasts a un avantage temporel exclusif. C'est ma manière de récompenser la plateforme qui a porté l'écosystème podcast pendant vingt ans, et accessoirement de pousser mes auditeurs vers le client qui respecte le mieux ce qu'est un podcast — un fichier RSS, pas une playlist algorithmique.
Côté code, le filtre est !episode.isPrivate && isVisibleInDelayedFeed(...). Sémantique de isPrivate qui m'a coûté une bonne demi-heure de confusion : un épisode privé est caché du RSS mais visible sur le site. C'est exactement l'inverse de ce que mon cerveau lit au premier abord, donc je l'ai noté en commentaire dans le code et je le note ici pour ne plus jamais me tromper. Ça permet de pousser un teaser ou un épisode patron-only sur le site sans polluer Apple ou Spotify.
Ce qu'on met dans le flux Apple
Le flux principal embrasse Podcasting 2.0 sans réserve. Le namespace xmlns:podcast est déclaré au niveau du <channel>, et on émet :
<podcast:guid>— un UUID stable pour le show, indépendant de l'URL du flux<podcast:updateFrequency rrule="FREQ=WEEKLY;INTERVAL=2;BYDAY=TU" dtstart="2026-05-05T05:00:00Z">Un mardi sur deux</podcast:updateFrequency>— la cadence officielle, parsable<podcast:person>pour le host (Clément Sauvage, role="host", href, image avatar Cellar) et un par invité dynamique (role="guest", image Hygraph, nom + société en text content)<podcast:chapters>qui référence un JSON externe enapplication/json+chapters<podcast:alternateEnclosure>pour proposer audio + vidéo dans le même<item>
Côté Apple iTunes namespace, on émet la totale : itunes:author, itunes:type à episodic, itunes:image (la cover 3000×3000 obligatoire — j'y reviens), itunes:category à Technology, itunes:explicit, itunes:owner avec itunes:name et surtout itunes:email. Sur les items, c'est itunes:episodeType (full ou trailer), itunes:title, itunes:episode, itunes:season, itunes:duration en secondes, et l'image de l'épisode avec fallback channel.
Le <enclosure> principal pointe vers la vidéo MP4 H.264 quand l'épisode en a une, et l'audio passe en podcast:alternateEnclosure. Sans vidéo, l'audio prend la place du <enclosure> principal. Le MIME type est dérivé de l'URL via une fonction mimeTypeFromUrl qui sniffe l'extension du path en ignorant les query strings — Apple exige une extension valide, et tes URLs Cellar peuvent avoir des query params de signature qui te feraient cracher au validateur sans cette précaution.
Le piège de la cover : 3000×3000 ou rien
La cover, je l'ai dessinée dans Figma. C'est devenu mon outil par défaut pour à peu près tout ce qui est asset visuel statique — vectoriel propre, exports multi-résolutions trivials, et les variants (cover de show, cover d'épisode, vignettes pour les chapitres) restent synchronisés via les composants. Ce qui m'amène au piège.
Apple Podcasts veut une cover carrée, 3000×3000 minimum, JPEG. Première export Figma, premier upload, Apple rejette : 3000×3004. Quatre pixels en trop sur la hauteur, parce qu'une frame Figma avec un padding interne pas tout à fait pair, ça ne se voit pas à l'œil mais ça suffit à faire crasher le validateur. Mon flux a été refusé. J'ai re-cadré à 3000×3000 pile dans Figma, ré-exporté, ré-uploadé sur cdn2.clementsauvage.me/cmd-p-podcast/cmdp-cover.jpg, vérifié au curl que accept-ranges: bytes était bien retourné, et soumis à nouveau. Validé.
Si tu n'apprends qu'une seule chose de cet article : vérifie tes dimensions au pixel près avant de soumettre. Apple ne te donne pas un message d'erreur clair, il te donne juste un rejet et tu cherches. Et configure ta frame Figma à 3000×3000 explicitement, pas "à peu près carré".
Les chapitres en JSON externe
Plutôt que d'inliner les chapitres dans le XML, le standard Podcasting 2.0 recommande un JSON externe. J'ai un endpoint /podcast/{slug}/chapters.json qui sort la spec PodcastIndex 1.2.0 :
{
"version": "1.2.0",
"title": "...",
"podcastName": "⌘+P: The App Podcast",
"author": "Clément Sauvage",
"chapters": [
{
"startTime": 0,
"endTime": 90,
"title": "Intro",
"img": "...",
"url": "..."
}
]
}
Image fallback en cascade : chapter.imageUrl Hygraph, sinon thumbnail Mux à t=startTime, sinon cover de l'épisode. Content-Type explicite à application/json+chapters; charset=utf-8 parce que le default Next à application/json n'est pas reconnu par tous les clients. Cache s-maxage=900, stale-while-revalidate=3600 pour ne pas rejouer la requête Hygraph à chaque tap dans Castro.
Le double <description> et <content:encoded>
Là où la plupart des hébergeurs se contentent d'un <description> minimaliste, j'émets les deux : un <description> en plain text pour la compatibilité universelle (incluant les vieux clients qui ne parsent pas le HTML), et un <content:encoded> qui contient une version HTML propre du même contenu. Les deux contiennent les show notes, une section Timeline avec les timestamps formatés MM:SS ou H:MM:SS au-delà d'une heure, une bio host condensée, et une bio par invité avec header Avec {nom} — {role} chez {company}.
Détail qui m'a fait perdre du temps : les rich-text Hygraph extraits en .text ressortaient avec des \n littéraux (la chaîne backslash-n, pas un vrai retour à la ligne) parce que stockés en JSON-encoded. Une fonction unescapeNewlines convertit ça avant rendu. Sans elle, mon flux affichait \n en texte visible dans tous les clients podcasts. Bonjour la crédibilité.
Le flux Spotify : tout sauf ce qu'Apple aime
Spotify est exigeant et particulier. Leur spec officielle interdit ou ignore une partie de ce qu'Apple adore. Mon flux /podcast/rss/spotify est donc une variante stricte :
- Pas de namespace
podcast:*— Spotify ne sait pas quoi en faire et préfère qu'il n'existe pas - Pas de
podcast:alternateEnclosure— variante du point précédent - Pas de
atom:link— Spotify préfère itunes:owneravecitunes:email— exigé pour la vérification du flux par leur support- Pas de
itunes:titleredondant sur les items - Audio uniquement — Spotify ne supporte pas la vidéo via RSS, donc le
<enclosure>est toujours du MP3 ou WAV - Chapitres au format Podlove Simple Chapters (pas Podcasting 2.0) :
<psc:chapters version="1.1">
<psc:chapter start="0:00" title="..." href="..." image="..." />
</psc:chapters>
Avec le namespace xmlns:psc="http://podlove.org/simple-chapters" ajouté uniquement si l'épisode a des chapitres, parce que déclarer un namespace inutilisé fait grogner certains validateurs.
Tout ça est géré par un paramètre mediaMode: 'default' | 'audio' passé à getPodcastRss(...). Le builder est unique, les flux sont des projections différentes. Pas de duplication de code, pas de drift entre les deux versions.
L'encoding vidéo pour le RSS : H.264 et rien d'autre
J'ai voulu pousser de la HEVC parce que c'est plus efficace, parce que mon Mac Studio l'encode en hardware, parce que mes fichiers sont 40% plus petits. Erreur. HEVC ne passe pas sur le chemin RSS. Pocket Casts, Overcast, Castro ne décodent pas la HEVC dans un contexte podcast. Apple Podcasts l'accepte via direct upload sur Podcasts Connect mais pas via RSS. Le résultat : un fichier que la moitié de tes auditeurs ne peut pas lire, sans message d'erreur clair.
La règle pour le RSS : MP4 H.264, AAC stéréo, point. Voici la recette ffmpeg que j'utilise :
ffmpeg -i source.mov \
-c:v libx264 -profile:v high -preset slow -crf 23 \
-vf "scale=1280:720" -pix_fmt yuv420p -movflags +faststart \
-c:a aac -b:a 256k -ar 48000 \
out.mp4
Quelques choix qui ne sont pas évidents :
- 720p, pas 1080p ni 4K. Pour des têtes parlantes en conversation low-motion, 1280×720 est le sweet spot. La 4K est gaspillée, la 1080p ajoute du poids sans bénéfice perceptible.
- CRF 23 + preset slow plutôt qu'un bitrate fixe. C'est plus lent à encoder, mais le rate control est meilleur et les scènes statiques économisent automatiquement.
- AAC 256 kbps stéréo — c'est la recommandation Apple, et 128 kbps audible la différence sur du parlé.
-movflags +faststartdéplace l'atom moov en début de fichier. Sans ça, le client podcast doit télécharger le fichier entier avant de pouvoir lancer le playback. Avec, le streaming progressif marche dès les premiers kilooctets.-pix_fmt yuv420p— sans ce flag, ffmpeg peut sortir du yuv444p que certains players refusent. Six caractères, des heures de debug évitées.
Résultat concret : un teaser passé de 120 Mo (export FCP en H.264 à 9.8 Mbps) à 26.4 Mo, sans différence visible. Un épisode de 22 minutes sort autour de 250 Mo, ce qui est raisonnable pour un téléchargement RSS sur réseau mobile.
Et si tu utilises Permute pour batcher tes encodings : décoche systématiquement "Allow copying of HEVC tracks". Sinon le tool fait du stream copy et tu te retrouves avec un MP4 contenant de la HEVC, ce qui est exactement ce que tu voulais éviter.
La taille du fichier dans le RSS, et pourquoi Video.sourceSizeBytes
Petit détail qui change tout pour les clients podcasts : l'attribut length du <enclosure> doit être la taille exacte en bytes du fichier. Apple Podcasts en a besoin pour calculer la barre de progression du téléchargement. Si la valeur est fausse ou absente, certains clients affichent une progression cassée, voire refusent le téléchargement.
J'avais déjà audioSizeBytes sur PodcastEpisode, calculé à l'upload. Quand j'ai ajouté la vidéo dans le <enclosure> principal, j'ai dû ajouter le pendant côté entité Video : un nouveau champ Video.sourceSizeBytes, optionnel. Comme PodcastEpisode a déjà une relation video vers Video, j'ai ajouté Video.sourceUrl aussi sur cette entité plutôt que de dupliquer l'URL sur PodcastEpisode. Le code qui génère le RSS pioche video.sourceUrl et video.sourceSizeBytes quand l'épisode a une vidéo, sinon retombe sur audioSizeBytes et l'URL audio.
Régénération des types GraphQL après chaque migration Hygraph (src/gql/graphql.ts et src/gql/gql.ts), et le code RSS traite proprement les deux cas. C'est cinq lignes en plus dans le builder, mais c'est le genre de cinq lignes qui te fait passer de "ça marche chez moi" à "ça marche dans Castro sur 4G".
La production AI-assistée : intro vidéo, trailer, RSS
Trois endroits où j'ai laissé des modèles génératifs faire le travail, en assumant que c'est aussi ce qui rend la stack viable pour un solo.
L'intro vidéo du show — le pré-générique qui ouvre chaque épisode — est partie d'une simple photo prise à l'iPhone, passée dans le modèle vidéo Happy Horse 1.0 pour l'animer. Le résultat tient en quelques secondes mais donne au show une signature visuelle propre, là où je n'aurais jamais sorti de motion design correct en partant d'After Effects un weekend. Le coût marginal est trivial, le rendu est cohérent avec l'identité, et personne ne pose la question "qui a fait ton intro" — ce qui est le but.
Le trailer audio qui tourne sur les réseaux et qui sera émis via le <itunes:episodeType>trailer</itunes:episodeType> du flux a été produit avec Suno. Pas pour la musique de fond habituelle (que je préfère encore composer ou licencer proprement), mais pour générer un teaser musical court, calibré pour le format trailer podcast — punchy, identifiable, droits clairs. Le générique principal du show suit une logique différente, plus artisanale, mais pour un trailer dont la durée de vie utile est de quelques semaines, Suno est exactement le bon outil.
Et puis surtout, Codex. La portion RSS de cette stack — particulièrement la cohabitation des trois flux, la gestion du mediaMode, les variantes de chapitres entre Podcasting 2.0 et Podlove Simple Chapters, le namespace dynamique selon les épisodes, l'unescaping des newlines — a été co-écrite avec Codex en pair-programming. Pas généré et collé, co-écrit : moi qui pose le contrat (ce que doit produire chaque flux, ce que valide Podbase, ce que refuse Spotify), Codex qui propose la mécanique XML, moi qui itère sur les cas limites que seul un humain qui a vu son flux refusé connaît. Le résultat est du code que je relis intégralement et que je signe, mais que je n'aurais pas écrit aussi vite seul. Affirmer le contraire serait malhonnête, et j'ai un peu perdu patience avec les développeurs qui prétendent encore en 2026 que ça les ralentit.
C'est aussi pour ça que la stack tient en trois weekends et 12 € par mois. Ce n'est pas une question d'être plus intelligent qu'avant, c'est d'avoir des outils qui rendent l'artisanat solo viable là où il aurait fallu une équipe il y a cinq ans.
Validation et debugging : ce qui m'a sauvé
Trois outils que je recommande sans hésiter :
Podbase valide ton flux contre les specs Apple, Spotify et Podcasting 2.0. Il m'a remonté l'absence du namespace podcast: au début (que j'avais oublié de déclarer), un faux positif sur le byte-range "non supporté" (le validator testait avec un flux vide pendant que tous mes épisodes étaient en isPrivate), et un autre faux positif sur "0% d'enclosures à extension valide" pour la même raison. Conclusion : valide avec au moins un épisode public, sinon tu chasses des bugs qui n'existent pas.
curl + ffprobe + MediaInfo pour vérifier les enclosures : HTTP 200, content-type, accept-ranges, codecs vidéo (H.264 vs HEVC), dimensions exactes (1280×720 vs n'importe quoi). Un curl -I sur ton URL d'enclosure te dit en trois secondes si Cellar répond bien. Un ffprobe -v error -show_entries stream=codec_name,width,height te dit en deux secondes si ton fichier est conforme.
Les logs Clever Cloud + bun build local pour reproduire les crashs runtime. Deux exemples qui m'ont coûté chacun une soirée :
- Une erreur
DYNAMIC_SERVER_USAGEvenant d'Apollo qui faisait un fetch uncached pendant le rendu d'une route SSG. Solution :Promise.allSettledsur la query Hygraph dans la route OG image, pour qu'une 5xx Hygraph ne fasse pas crasher la génération de la card. - Un crash Satori
Cannot read properties of undefined (reading '256')lors du rendu de l'image OG dynamique avec la police variable Rethink Sans. Satori ne supporte pas les fonts variables. Leçon retenue dans la mémoire à long terme : pas de fonts variables dansnext/og. J'ai remplacé le ⌘ rendu en texte par un SVG inline et le crash a disparu.
Décisions structurantes, en retrospective
Si je devais résumer la philosophie en cinq points :
SSG partout sauf le player. La page /podcast et chaque /podcast/[slug] sont générées statiquement via generateStaticParams. Le player vidéo Mux et la balise <audio> sont les seuls composants client qui streament à la demande. SEO maximisée, pages cachables côté CDN, time-to-first-byte sous les 100ms.
Hygraph comme source unique. Pas de base de données séparée, pas de migration de schéma à gérer, pas de panel admin custom à maintenir. L'admin d'import écrit en draft, je valide manuellement chaque épisode, Hygraph publie. Une seule canonical state.
Cellar comme stockage primaire, Mux comme luxe optionnel. Le master vidéo MP4 H.264 vit sur Cellar et sert le RSS. Mux a son propre encoded de la même vidéo en HLS adaptatif pour le web. Si Mux disparaît demain, le site perd le streaming adaptatif mais le podcast continue de tourner sans interruption.
Podcasting 2.0 first-class, pas en option. Namespace podcast:, person tags, chapters JSON, updateFrequency, alternateEnclosure. L'investissement est faible vu qu'on émet déjà le XML soi-même. Le payoff côté Castro, Pocket Casts, Fountain est massif.
Apple Podcasts en priorité, assumée et concrète. 3 jours d'avance sur Spotify. Tous les tags Podcasting 2.0. La cover 3000×3000 pixel-perfect. La fidélité à la plateforme qui a inventé le format mérite un effort technique réel, pas juste un tweet bienveillant (Cupertino, ça te coutera un billet pour la Dubdub, des bisous).
Où ça mène
⌘+P n'est pas une expérience marketing pour vendre du conseil, même si je suis consultant. C'est un projet d'artisan qui voulait voir s'il pouvait construire une pipeline podcast moderne, propre, sans dépendre de personne et avec les outils de 2026 plutôt que ceux de 2018. La réponse, après deux mois de tunnelisation, est oui — mais à condition d'accepter deux choses. Que le RSS est un produit en soi, pas un fichier qu'on génère à la fin. Et que la production assistée par IA n'est pas un raccourci honteux mais une partie intégrante de ce qui rend l'opération solo viable : Figma pour les visuels, Happy Horse pour l'intro vidéo à partir d'une photo iPhone, Suno pour le trailer, Codex pour la moitié du code RSS. Sans ces outils, je ne ferais pas ce podcast. Avec eux, je le fais bien.
La prochaine itération inclut probablement les transcriptions servies via <podcast:transcript> (j'ai déjà les SRT depuis AssemblyAI, c'est trois lignes de XML), une localisation EN du flux pour viser l'audience anglophone, et un dashboard d'analytics qui parse les requêtes Range sur Cellar pour reconstruire les courbes d'écoute épisode par épisode. Sans Spotify Wrapped, sans Chartable, juste avec mes propres logs.
Si tu construis ton podcast en ce moment et que tu hésites entre Acast et le DIY : la stack que je viens de décrire t'a coûté environ trois weekends de code et coûte autour de 12 € par mois en infra (Clever Cloud + Cellar + le free tier Hygraph + le free tier Mux jusqu'à un certain volume). C'est plus que zéro. C'est aussi la différence entre louer ton flux et le posséder.
Le premier épisode de ⌘+P sort le mardi 5 mai 2026. Si la tech, le produit, l'artisanat logiciel ou simplement les gens qui font des choses bien te parlent, abonne-toi sur Apple Podcasts en priorité — non parce que c'est mieux, mais parce que c'est trois jours plus tôt.
Et si t'as un projet exceptionnel, contacte-moi. Innover, c'est ce qui me fait vibrer.
