Interfaccia Third-Party

Crea uno strumento che BakoshApp possa pilotare: esponi quattro endpoint HTTP su una porta locale, e il tuo programma reagirà a regali, like, follow e chat di TikTok e Kick.

BakoshApp può eseguire azioni all'interno del tuo programma. Il tuo strumento espone una piccola API HTTP su una porta locale; BakoshApp legge la tua lista di azioni e ne chiama una ogni volta che un evento TikTok o Kick corrisponde al trigger dell'utente. Tutto ciò che puoi controllare da codice — luci smart, un microcontrollore, una soundboard, un altro gioco, il tuo bot — può reagire a una live senza un mod di BakoshApp.

Come funziona nell'insieme

  1. Il tuo strumento è in ascolto su http://127.0.0.1:8833.
  2. L'utente lo collega in Impostazioni → Third-Party (host e porta) e lo verifica con Prova connessione.
  3. Nella scheda Azioni di un mod, l'utente clicca su Aggiungi nuovo, sceglie un trigger e in Tutte le azioni → Esterni configura una Third-Party Action: BakoshApp compila due liste con le tue categorie e azioni.
  4. Ad ogni evento corrispondente, BakoshApp chiama il tuo strumento, e il tuo codice fa il resto.

La connessione è a senso unico: BakoshApp chiama te, mai il contrario.

Porta e indirizzo

  • 8833 è la porta predefinita. L'utente può cambiarla in Impostazioni → Third-Party; se usi una porta diversa, indica ai tuoi utenti quale inserire.
  • La porta 8832 non può essere usata: BakoshApp stesso è in ascolto lì (è così che TikFinity trova BakoshApp), e l'impostazione la rifiuta.
  • Non c'è autenticazione. Resta in ascolto su 127.0.0.1, non su 0.0.0.0, in modo che l'API non sia raggiungibile dalla rete.
  • BakoshApp usa sempre HTTP semplice.

Endpoint

Il tuo strumento deve fornire tutti e quattro. Ogni risposta è in JSON con un membro data.

1. Info app

Identifica il tuo strumento. BakoshApp lo mostra come "Connesso con Mock Tool 1.0 di Bakosh" in Impostazioni e nel configuratore delle azioni.

GET /api/app/info
{ "data": { "name": "Mock Tool", "version": "1.0", "author": "Bakosh" } }

2. Categorie

La prima lista nel configuratore.

GET /api/features/categories
{
  "data": [
    { "categoryId": "smart_device_control", "categoryName": "Control Smart Devices" },
    { "categoryId": "serial_port_control",  "categoryName": "Control Serial Port" }
  ]
}

3. Azioni

La seconda lista: le azioni di una categoria. categoryId è URL-encoded.

GET /api/features/actions?categoryId=smart_device_control
{
  "data": [
    { "actionId": "turn_lights_on",  "actionName": "Turn Lights On" },
    { "actionId": "turn_lights_off", "actionName": "Turn Lights Off" }
  ]
}

Le liste mostrano i tuoi elementi nell'ordine in cui li restituisci. Un'azione che l'utente ha già salvato ma che non restituisci più resta in cima alla lista, così non cambia silenziosamente.

Avviso

categoryId e actionId sono tutto ciò che BakoshApp memorizza per un'azione configurata. Mantienili stabili: rinominare un id rompe le configurazioni esistenti. I nomi servono solo per la visualizzazione e possono cambiare in qualsiasi momento.

4. Esecuzione

Chiamato ogni volta che un evento corrispondente esegue l'azione.

POST /api/features/actions/exec
{
  "categoryId": "smart_device_control",
  "actionId": "turn_lights_on",
  "context": {
    "triggerTypeId": 4,
    "eventType": "gift",
    "source": "eulerstream",
    "platform": "tiktok",
    "userId": "123456789",
    "username": "testuser",
    "nickname": "Test User",
    "giftName": "Rose",
    "giftId": 5655,
    "repeatCount": 3,
    "diamondCount": 1,
    "coins": 1,
    "profilePictureUrl": "https://…"
  }
}

Rispondi con un array data vuoto una volta accettata la richiesta:

{ "data": [] }

Tempistiche

  • BakoshApp attende fino a 5 secondi per i tre endpoint GET e 10 secondi per exec. Una richiesta che fallisce o va in timeout non viene ripetuta.
  • Se l'azione ha Quantità superiore a 1, BakoshApp chiama exec altrettante volte, una dopo l'altra: attende la tua risposta, poi l'Intervallo della riga, poi chiama di nuovo.
  • Le chiamate per la stessa riga arrivano una alla volta; righe diverse possono chiamarti in parallelo.

Quindi rispondi rapidamente ed esegui i lavori lenti in background — gli spettatori possono inviare regali più velocemente di quanto si muova una porta seriale.

L'oggetto context

context descrive l'evento che ha eseguito l'azione. Sono presenti solo i campi che esistono per quell'evento — verifica prima di leggerli.

CampoTipoPresente
triggerTypeIdnumerosempre — vedi sotto
eventTypestringasempre — gift, like, chat, follow, share, joined, subscribe, tikfinity o test
sourcestringasempre — eulerstream (TikTok), kick, tikfinity o test
platformstringaEventi TikTok e Kick — tiktok o kick
usernamestringasempre — l'handle dello spettatore
nicknamestringaEventi TikTok e Kick — il nome visualizzato
userIdstringaEventi TikTok e Kick
profilePictureUrlstringadi solito (i link agli avatar di TikTok scadono)
commentstringamessaggi in chat; su Kick anche il messaggio allegato a un regalo
giftNamestringaregali
giftIdnumeroRegali TikTok
repeatCountnumeroRegali TikTok — regali nella serie; abbonamenti regalati su Kick — numero di destinatari
diamondCountnumeroregali — valore in Diamonds (TikTok) o prezzo in Kicks (Kick)
coinsnumerocome diamondCount
likeCountnumerolike
subMonthnumeroabbonamenti

Gli eventi inoltrati da TikFinity contengono solo triggerTypeId (sempre 0), source, eventType e username.

Tipi di trigger

triggerTypeId è il tipo di trigger configurato dall'utente, così un regalo scelto per nome e uno individuato per valore vengono distinti:

IdTrigger
1Condivisione
3Min-Max (intervallo di valore del regalo)
4Regalo
6Entrato
7Like
9Segui
10Subscribe / Super Fan
11Chat
0TikFinity, o qualsiasi altra cosa

Tratta gli id sconosciuti come 0; potrebbero esserne aggiunti altri.

Il pulsante Prova

Prova sulla riga dell'azione (e la sua scorciatoia) chiama exec con dati di esempio: source e eventType sono test, triggerTypeId proviene dal trigger della riga, lo spettatore è bakosh_app, e il regalo è una Rose (giftId 5655). Non c'è platform.

Segnalare i problemi

Restituisci un message per descrivere cosa è andato storto:

{ "message": "Serial port COM3 is not available" }
  • Sugli endpoint GET, qualsiasi message fa sì che BakoshApp tratti la risposta come un errore, anche con HTTP 200.
  • Su exec, il message viene scritto nella console e nel file di log di BakoshApp come avviso. L'utente non riceve alcun popup.

Vengono rispettati anche gli status HTTP di errore; senza un message, il log mostra solo il codice di stato.

Funzionare anche con TikFinity

L'interfaccia corrisponde all'interfaccia third-party di TikFinity — gli stessi quattro percorsi e nomi di campo — quindi uno strumento può servire entrambi. Le porte differiscono: TikFinity cerca gli strumenti sulla 8832, che BakoshApp occupa mentre è in esecuzione, quindi assegna a BakoshApp un'altra porta.

TikFinity è una web app e ha bisogno di header CORS (Access-Control-Allow-Origin: * e simili) oltre che di risposte alle richieste preflight OPTIONS. BakoshApp non ne ha bisogno, ma inviarli non fa danno. BakoshApp invia più campi context di TikFinity — ignora quelli che non usi.

Uno strumento completo e funzionante

Nessuna dipendenza — salvalo come tool.mjs ed esegui node tool.mjs:

import http from 'node:http';
 
const PORT = 8833;
 
const APP_INFO = { name: 'Mock Tool', version: '1.0', author: 'Bakosh' };
 
const CATALOG = [
  {
    categoryId: 'smart_device_control',
    categoryName: 'Control Smart Devices',
    actions: [
      { actionId: 'turn_lights_on', actionName: 'Turn Lights On' },
      { actionId: 'turn_lights_off', actionName: 'Turn Lights Off' },
    ],
  },
];
 
// Wildcard CORS keeps the same tool usable from TikFinity as well.
const CORS = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Headers': '*',
  'Access-Control-Allow-Methods': '*',
};
 
const send = (res, status, body) => {
  res.writeHead(status, { 'Content-Type': 'application/json', ...CORS });
  res.end(JSON.stringify(body));
};
 
const readBody = (req) =>
  new Promise((resolve) => {
    let raw = '';
    req.on('data', (c) => { raw += c; });
    req.on('end', () => { try { resolve(JSON.parse(raw || '{}')); } catch { resolve({}); } });
  });
 
// Your actual work goes here. Return a string to report a problem.
function runAction(categoryId, actionId, context) {
  console.log(`${categoryId}/${actionId} fired by ${context.username ?? 'someone'} on ${context.platform ?? context.source}`);
  // turnLightsOn() …
  return null;
}
 
http.createServer(async (req, res) => {
  const url = new URL(req.url, `http://127.0.0.1:${PORT}`);
 
  if (req.method === 'OPTIONS') {           // preflight (TikFinity only)
    res.writeHead(204, CORS);
    return res.end();
  }
 
  if (req.method === 'GET' && url.pathname === '/api/app/info') {
    return send(res, 200, { data: APP_INFO });
  }
 
  if (req.method === 'GET' && url.pathname === '/api/features/categories') {
    return send(res, 200, {
      data: CATALOG.map(({ categoryId, categoryName }) => ({ categoryId, categoryName })),
    });
  }
 
  if (req.method === 'GET' && url.pathname === '/api/features/actions') {
    const cat = CATALOG.find((c) => c.categoryId === url.searchParams.get('categoryId'));
    return send(res, 200, { data: cat ? cat.actions : [] });
  }
 
  if (req.method === 'POST' && url.pathname === '/api/features/actions/exec') {
    const body = await readBody(req);
    const problem = runAction(body.categoryId ?? '', body.actionId ?? '', body.context ?? {});
    return problem ? send(res, 200, { message: problem }) : send(res, 200, { data: [] });
  }
 
  send(res, 404, { message: `No such endpoint: ${url.pathname}` });
}).listen(PORT, '127.0.0.1', () => console.log(`Listening on http://127.0.0.1:${PORT}`));

Testare il tuo strumento

  1. Avvia il tuo strumento.
  2. In BakoshApp, apri Impostazioni → Third-Party, verifica host e porta, e clicca su Prova connessione. Dovresti vedere il nome, la versione e l'autore del tuo strumento.
  3. Nella scheda Azioni di un mod, clicca su Aggiungi nuovo, scegli un trigger e clicca su Avanti. In Tutte le azioni → Esterni, clicca su Configure accanto a Third-Party Action, scegli la tua categoria e azione, e salva.
  4. Clicca su Prova sulla nuova riga — il tuo strumento riceve un exec con eventType: "test".
  5. Vai in diretta e verifica che arrivino eventi reali.

Se il configuratore dice "Impossibile connettersi! Controlla la tua integrazione.", verifica che lo strumento sia in ascolto su 127.0.0.1, che la porta corrisponda a quella in Impostazioni, e che GET /api/app/info restituisca la risposta dentro data.