Skip to content

kapp.chat

Lire et écrire dans le chat Twitch du streamer, et réagir aux messages / commandes des viewers.

Service partagé appli + widget : l'API est identique. Seul le wrapper d'exécution diffère (côté widget : window.executeWidgetFunction ; côté appli : script.js après l'event AppliLoaded).

Quand l'utiliser (vs alternative)

  • kapp.chat.say() : faire parler le bot dans le chat.
  • kapp.chat.onMessage / onCommand : réagir en continu au chat (ex. compteur de commande). Côté widget déclenché PAR une commande configurée, lis plutôt les arguments typés kapp.arguments.<key>.
  • kapp.chat.onActivityChange / kapp.chat.activity : réagir au niveau d'activité du chat (calme/animé), pas à chaque message individuel.
  • Pour du TTS, c'est kapp.textToSpeech ; pour une notif écran, kapp.overlay.

Méthodes

  • say(message: string): Promise<void> — envoie un message dans le chat (le bot parle). async.
  • announce(message: string, color = 'primary'): Promise<void> — annonce Twitch colorée (primary | blue | green | orange | purple). async.
  • shoutout(channel: string): Promise<void>/shoutout Twitch vers une chaîne. async.
  • getChatEvents(count = 100): Promise<ChatEvent[]> — derniers messages. async.
  • getActiveUsers(options = {}): User[] — viewers actifs récemment. Options : { time, excludes, count, randomize, property }. sync.
  • onMessage(callback): voidcallback(user: User, ev: ChatEvent) à chaque message (hors commandes).
  • onCommand(keywords, callback, options = {}): voidkeywords: string | string[] | null (sans le symbole !). callback(user, ev). options: { once?: boolean, grantedRole?: 'admin'|'mod'|… }. null = toutes les commandes.
  • onActivityChange(callback): voidcallback(activity: ChatActivity) à chaque changement de niveau d'activité du chat.
  • activity: ChatActivity | null — état d'activité courant, lisible en synchrone à tout moment (null tant que rien n'a encore été reçu, au tout début de l'exécution). sync, propriété (pas une méthode).
  • getActivityState(): ChatActivityState — raccourci équivalent à activity?.state ?? 'calm' (jamais null). sync.

ChatEvent (objet ev) : ev.getMessage(), ev.getCommand(), ev.getArg(n) (1-based), ev.getArgsCount(), ev.isCommand(), ev.isCheer(), ev.getCheer(), await ev.respond('texte'), ev.getTwitchTags() (tags IRC bruts : badges, color, bits…). ev.getArg(n) renvoie un ChatEventArg : .string(), .number() (entier ≥ 0 sinon null), await .user().

Badges / abonnement de l'auteur (sync) : ev.getBadges() (liste {set_id, version}), ev.isSubscriber(), ev.getSubscriberMonths() (mois d'abo exacts), ev.getSubscriberTier() (1|2|3|null). Pour les afficher en images : await kapp.emotes.getBadges(ev) (voir emotes.md).

Niveau d'activité du chat (ChatActivity)

Le niveau d'activité est calculé par la plateforme à partir du débit récent de messages relatif à la baseline propre du channel (pas un seuil absolu global) : un channel habituellement très bavard et un channel calme n'atteignent pas hot au même débit brut.

  • state / previous : 'silent' | 'calm' | 'active' | 'hot' (croissant, quiétude → animation), état courant et état juste avant ce changement.
  • rate : débit de messages courant (messages / unité de temps). baseline : débit habituel du channel. ratio : rate / baseline.
  • ts : timestamp (ms) du calcul.
  • activity.isSilent() / .isActive() / .isHot() : raccourcis sur state.
  • activity.hasRisen() / .hasFallen() : le niveau vient-il de monter/descendre par rapport à previous (ex. calmactive = hasRisen() === true).
js
kapp.chat.onActivityChange((activity) => {
    if (activity.hasRisen() && activity.isHot()) {
        kapp.overlay.notification('Le chat est en feu ! 🔥');
    }
});

Identité du bot (kapp.channel.bot)

Le compte Twitch qui poste réellement les messages de say() (le bot global Kappapps, ou le compte du streamer si un bot perso est configuré) est exposé en synchrone :

  • kapp.channel.bot : { login, display_name, profile_image_url } | null.

Sert surtout à exclure le bot d'un tirage ou à filtrer ses propres messages :

js
// tirer 1 viewer actif, hors streamer et hors bot
const [gagnant] = kapp.chat.getActiveUsers({
    count: 1,
    randomize: true,
    excludes: [
        { login: kapp.channel.twitchUser.login },
        { login: kapp.channel.bot?.login },
    ],
});

bot peut être null (identité indisponible) → toujours l'accéder en kapp.channel.bot?.login.

Exemple (V2, exécutable)

js
// Réagit à !so <pseudo> pendant 30 s (corps d'exécution widget ou appli)
kapp.chat.onCommand('so', async (user, ev) => {
    const target = ev.getArg(1).string();   // 1er argument (1-based)
    if (target) {
        await kapp.chat.say(`📣 Allez voir ${target} !`);
    }
});

Pièges

  • onMessage / onCommand ne sont PAS async : ils enregistrent un écouteur. Le travail dans le callback, lui, est async → await.
  • keywords s'écrit sans le symbole de commande ('so', pas '!so').
  • getArg(n) est 1-based. .number() rejette les décimaux/négatifs → pour un montant : Number(ev.getArg(1).string()).
  • V1 mort : kapp.onChatMessage / kapp.onChatCommand n'existent plus.
  • kapp.chat.activity peut être null juste au démarrage (avant le premier calcul reçu de la plateforme) → activity?.isHot(), ou utilise getActivityState() qui renvoie toujours une valeur ('calm' par défaut).
  • Les seuils silent/calm/active/hot sont relatifs à la baseline du channel, pas un débit brut universel : ne compare pas rate entre deux channels différents, compare plutôt state/ratio.