Appearance
kapp.announces
Diffuser une annonce sur plusieurs canaux (chat, écran, voix, Discord…). Pluriel : kapp.announces. C'est une façade pratique au-dessus de chat / overlay / textToSpeech.
Service partagé appli + widget : API identique.
Quand l'utiliser (vs alternative)
- Une annonce que le streamer a configurée dans tes préférences →
play('chemin.de.la.pref'). C'est le cas courant : lui choisit le contenu et les canaux, toi le moment. - Raccourcis simples :
twitchChat,screenNotification,screenAnnounce,speech. - Pour cibler UN seul canal précis, tu peux aussi appeler directement le service dédié (
kapp.chat.say,kapp.overlay.notification,kapp.textToSpeech.speech). announce(data)= format riche multi-canal que TON appli fabrique (avancé, rarement nécessaire).
Méthodes
play(preference: string, tags = {}, title = null, metadata = {}): Promise<void>— joue l'annonce configurée par le streamer, désignée par le chemin de sa préférence. async.twitchChat(message: string): Promise<void>— écrit dans le chat (=kapp.chat.say). async.twitchAnnounce(message, color = 'primary'): Promise<void>— annonce Twitch colorée. async.speech(message, moderate = false): Promise<void>— TTS (=kapp.textToSpeech.speech). async.screenNotification(message, options = {}): Promise<void>— notification à l'écran.options:{ duration?, html?, title?, title_html?, target?, visual? }. async.screenAnnounce(message, options = {}): Promise<void>— grande annonce à l'écran. Mêmesoptions. async.announce(data: AnnounceCreateData, tags = {}, title = null, metadata = {}): Promise<AnnounceModel>— annonce multi-canal fabriquée par l'appli. async.
Exemple (V2, exécutable)
js
// Le streamer a réglé une préférence `announces` nommée `messages.onWin` :
// c'est lui qui décide chat / écran / voix / Discord, l'appli dit juste « maintenant ».
await kapp.announces.play('messages.onWin', { user: 'Sam', amount: '250' });
await kapp.announces.screenNotification('Nouveau record battu !', {
duration: 5,
title: 'GG',
});Deux façons de déclencher une annonce
play('chemin') | announce({...}) | |
|---|---|---|
| D'où vient le contenu | des réglages du streamer, lus en base | de ton code |
| Scope à déclarer | announces:play, un seul | un par track diffusée (chat:write, discord:message, dashboard-event:create…) |
| Track Discord | fonctionne, le webhook reste côté serveur | il faut fournir TON webhook |
Lire la préférence puis la passer à announce() revient exactement au même que play() : la valeur porte sa référence, la plateforme la reconnaît. Ces deux lignes sont équivalentes — la seconde est juste plus explicite.
js
await kapp.announces.announce(kapp.preferences.get('messages.onWin'), { user: 'Sam' });
await kapp.announces.play('messages.onWin', { user: 'Sam' });Tracks
Une annonce diffuse le même événement sur plusieurs « tracks », chacune activable indépendamment. La colonne « scope » ne concerne que announce({...}) : avec play(), un seul scope suffit (announces:play), puisque c'est le streamer qui a écrit le contenu.
| Track | Effet | Champ propre | Scope (payload libre) |
|---|---|---|---|
chatMessage | message dans le chat Twitch | — | chat:write |
chatAnnounce | annonce Twitch colorée | color | chat:write |
chatAction | message /me | — | chat:write |
screenNotification | notification à l'écran | options | — |
screenAnnounce | grande annonce à l'écran | options | — |
textToSpeech | lu à voix haute | — | — |
channelDashboardEvent | événement dans le dashboard du streamer | — | dashboard-event:create |
discord | message posté sur un webhook Discord | webhook | discord:message |
service | relais vers des services d'appli | services | app-service:call |
- Chaque track accepte des
variations: une est tirée au sort, sinon on retombe surmessages. channelDashboardEventdécoupe le message : première ligne = titre, reste = corps.discordne part pas si aucun webhook n'est configuré.- Si aucune track n'est activée, l'annonce se replie sur
k.channel.preferences.default_announce_tracks. - Une track qui échoue n'empêche pas les autres de se jouer.
- Chat, annonce Twitch,
/meet Discord attendent lestream_delaydu channel ; les autres partent tout de suite.
Tags de message (#tag#)
Les tags que tu passes en 2e argument sont ajoutés à ceux que la plateforme fournit d'office. Un tag inconnu reste écrit en clair dans le message — c'est ainsi qu'on repère une faute de frappe plutôt que de perdre un bout de phrase.
| Tag | Contenu |
|---|---|
#channel_name# / #channel_display_name# | nom d'affichage du streamer |
#channel_login# | login Twitch |
#currency_name# / #channel_currency_name# | nom de la monnaie du channel |
#currency_symbol# / #channel_currency_symbol# | symbole de la monnaie |
#command_symbol# / #channel_command_symbol# | préfixe des commandes chat |
#channel_language# | langue du channel (fr / en) |
#twitch_stream_title# | titre du stream |
#twitch_stream_category# | catégorie Twitch en cours |
#twitch_stream_chatters# | nombre de chatteurs actifs |
#twitch_stream_messages# | messages échangés depuis le début du live |
#twitch_stream_started_from# | durée du live, 2h30m12s |
#last_message# | le message de base tiré pour cette annonce |
Les deux conventions de nommage (#currency_name# et #channel_currency_name#) sont servies : elles viennent de deux moteurs historiques, les deux marchent.
#twitch_stream_started_at#n'existe plus. Il promettait une heure de début, que le serveur ne peut pas rendre correctement faute de fuseau horaire de channel — et il écrivait en réalité une durée absurde. Pour parler de l'ancienneté du live, utilise#twitch_stream_started_from#.
Habillage : le streamer décide, l'appli décrit
L'appli fournit le contenu de l'événement ; les couleurs, la police, la position et les animations viennent de l'habillage configuré par le streamer dans son dashboard. Il n'existe donc aucune option de style (accentColor, motion, variant…) : toute clé hors contrat est ignorée en silence côté serveur.
visual — joindre une image à l'événement
js
// Une image de la médiathèque du channel, désignée par son token (jamais une URL).
await kapp.announces.screenAnnounce('Nouveau palier atteint !', {
visual: { type: 'image', source: 'channel-media', token: media.token, shape: 'circle' },
});
// Une image livrée avec l'appli, dans son dossier `public_assets`.
await kapp.announces.screenAnnounce('Victoire !', {
visual: { type: 'image', source: 'app-asset', file: 'icons/trophy.png' },
});
// La photo de profil Twitch du viewer concerné.
await kapp.announces.screenNotification(`${user.displayName} vient de suivre !`, {
visual: { type: 'profile', url: await user.getProfileImageUrl() },
});Sources acceptées : channel-media, library-media (bibliothèque publique), app-asset (fichier de l'appli, chemin relatif à public_assets) et profile (CDN Twitch uniquement). Aucune URL externe n'est acceptée, quelle que soit la source.
Pour app-asset, c'est la version de l'appli installée sur le channel qui est servie : le chemin ne peut pas sortir de public_assets, et seules les images matricielles (png, jpg, jpeg, gif, webp, avif) sont acceptées — pas de SVG.
Un visuel non résolu — jeton inconnu, média d'un autre channel, URL externe, chemin de fichier hors contrat — est simplement retiré : le texte reste affiché.
target — dans quel overlay jouer
main(défaut) : l'overlay principal, même si l'appli tourne dans un overlay secondaire.current: l'overlay qui héberge réellement l'appli, résolu côté serveur.
Une appli ne peut jamais désigner un overlay arbitraire. Si l'overlay ciblé n'est plus ouvert, l'appel échoue avec OVERLAY_NOT_FOUND — il n'y a pas de repli silencieux vers main.
Pièges
options.durationest en secondes (et non en millisecondes, contrairement à ce qu'indiquaient les anciennes versions de cette doc). Une valeur hors bornes est ramenée dans les clous : 1 à 180 s pour une annonce, 1 à 60 s pour une notification.html: truereste supporté, mais le contenu est nettoyé avant affichage : la mise en forme passe, pas les scripts ni les gestionnaires d'événements.announce()attend un objetAnnounceCreateDatastructuré — pour un simple texte, préfèrescreenNotification/screenAnnounce. Ses tracksscreenNotification/screenAnnounceacceptent leurs propresoptions.- La diffusion est asynchrone.
awaitveut dire « la plateforme a accepté », pas « c'est déjà à l'écran » : le délai de stream et l'enrichissement IA passent par une file côté serveur. announce()ne rejette jamais (un refus part dans la console de l'overlay) ;play()rejette. Si tu veux réagir à un mauvais chemin ou un scope manquant, utiliseplay().- Le webhook Discord ne t'est jamais donné. Dans une préférence d'annonce,
discord.webhookest un booléen (« le streamer en a configuré un, ou non »). Pour poster sur Discord avec ton propre webhook, il fautannounce({...})et le scopediscord:message. - Ne modifie pas une préférence d'annonce avant de la jouer : elle porte une référence (
_ref) et c'est la version en base qui sera diffusée, tes surcharges seront ignorées. Si tu veux vraiment décider du contenu, construis un objet littéral. - V1 mort :
kapp.playAnnounceSet(...)n'existe plus.