Skip to content

kapp.announces ​

Les consignes d'enrichissement utilisent {…} ; les consignes vocales libres utilisent […], selon le contrat TTS commun. Tous les blocs entre crochets restent sur la piste TTS et sont retirés des pistes non vocales, y compris après résolution de #last_message#. Les crochets comme [VIP] sont aussi des consignes : éviter cette notation pour une mention destinée à toutes les pistes.

Le message commun et les variantes des pistes texte utilisent des champs texte classiques. L’éditeur vocal avec choix de voix, raccourcis de consignes et effets est réservé aux variantes de la piste TTS.

Diffuser une annonce sur plusieurs canaux (chat, écran, voix, Discord…). Pluriel : kapp.announces. La diffusion multicanal passe par un moteur backend unique ; ne pas reconstruire son orchestration avec plusieurs appels client.

Service partagé appli + widget. Les sources de configuration et les permissions diffèrent selon le contexte ; les exemples de préférences ci-dessous sont réservés aux applis. Voir permissions.

Quand l'utiliser (vs alternative) ​

  • Appli : annonce configurée dans ses préférences → play('chemin.de.la.pref'). Le streamer choisit le contenu et les canaux, le code choisit le moment.
  • Widget : sa propre annonce configurée → play('announces'), sans service de préférences. Le runtime la joue déjà si la sortie intégrée est active : ne pas la jouer deux fois. Les références flowchart:<id> désignent un nœud d’annonce de son propre flowchart.
  • 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 code fabrique (avancé, rarement nécessaire).

Méthodes ​

  • play(preference: string, tags = {}, title = null, metadata = {}): Promise<void> — joue l'annonce configurée par le streamer : chemin de préférence d'appli, ou référence du widget indiquée ci-dessus. 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) ou speech(message, { moderate, target: 'main' | 'current' }): Promise<void> — alias de kapp.textToSpeech.speech. Confirme l’acceptation, sans attendre la lecture. La piste textToSpeech d’une annonce accepte également options.target ; current nécessite un contexte overlay d’origine.
  • 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êmes options. async.
  • announce(data: AnnounceCreateData, tags = {}, title = null, metadata = {}): Promise<AnnounceModel> — annonce multi-canal fabriquée par le code. async.

Exemple commun (V2) ​

js
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 contenudes réglages du streamer, lus en basede ton code
Scope à déclarer dans une appliannounces:play, un seulun par track diffusée (chat:write, discord:message, dashboard-event:create…)
Track Discordfonctionne, le webhook reste côté serveuril faut fournir TON webhook

Appli uniquement : une préférence passée à announce() déclenche la même configuration serveur que play(), grâce à sa référence. Le traitement des erreurs diffère : play() rejette, announce() absorbe le refus et le signale en console. Pour la configuration, lire préférences d’annonce. Un widget n’a ni prefs ni kapp.preferences.

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. Ces scopes sont ceux du manifeste d’une appli ; les widgets n’en déclarent pas.

TrackEffetChamp propreScope (payload libre)
chatMessagemessage dans le chat Twitch—chat:write
chatAnnounceannonce Twitch coloréecolorchat:write
chatActionmessage /me—chat:write
screenNotificationnotification à l'écranoptions—
screenAnnouncegrande annonce à l'écranoptions—
textToSpeechlu à voix haute——
channelDashboardEventévénement dans le dashboard du streamer—dashboard-event:create
discordmessage posté sur un webhook Discordwebhookdiscord:message
servicerelais vers des services d'appliservicesapp-service:call
  • Chaque track accepte des variations : une est tirée au sort, sinon on retombe sur messages.
  • channelDashboardEvent découpe le message : première ligne = titre, reste = corps.
  • discord ne 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, /me et Discord attendent le stream_delay du 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.

TagContenu
#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' },
});

// Appli uniquement : une image livrée 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.getDisplayName()} 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.duration est 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: true reste 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 objet AnnounceCreateData structuré — pour un simple texte, préfère screenNotification / screenAnnounce. Ses tracks screenNotification / screenAnnounce acceptent leurs propres options.
  • La diffusion est asynchrone. await veut 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, utilise play().
  • Le webhook Discord ne t'est jamais donné. Dans une préférence d'annonce, discord.webhook est un booléen (« le streamer en a configuré un, ou non »). Pour poster sur Discord avec ton propre webhook, il faut announce({...}) et le scope discord: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.