Appearance
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.jsaprès l'eventAppliLoaded).
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éskapp.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>—/shoutoutTwitch 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): void—callback(user: User, ev: ChatEvent)à chaque message (hors commandes).onCommand(keywords, callback, options = {}): void—keywords:string | string[] | null(sans le symbole!).callback(user, ev).options:{ once?: boolean, grantedRole?: 'admin'|'mod'|… }.null= toutes les commandes.onActivityChange(callback): void—callback(activity: ChatActivity)à chaque changement de niveau d'activité du chat.activity: ChatActivity | null— état d'activité courant, lisible en synchrone à tout moment (nulltant 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'(jamaisnull). 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 surstate.activity.hasRisen()/.hasFallen(): le niveau vient-il de monter/descendre par rapport àprevious(ex.calm→active=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 },
],
});
botpeut êtrenull(identité indisponible) → toujours l'accéder enkapp.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/onCommandne sont PAS async : ils enregistrent un écouteur. Le travail dans le callback, lui, est async →await.keywordss'é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.onChatCommandn'existent plus. kapp.chat.activitypeut êtrenulljuste au démarrage (avant le premier calcul reçu de la plateforme) →activity?.isHot(), ou utilisegetActivityState()qui renvoie toujours une valeur ('calm'par défaut).- Les seuils
silent/calm/active/hotsont relatifs à la baseline du channel, pas un débit brut universel : ne compare pasrateentre deux channels différents, compare plutôtstate/ratio.