Third-Party Interface
Gumawa ng tool na madadala ng BakoshApp: mag-serve ng apat na HTTP endpoint sa isang local port, at tumutugon ang program mo sa mga regalo, like, follow at chat sa TikTok at Kick.
Maaaring magpatakbo ang BakoshApp ng mga aksyon sa loob ng sarili mong program. Nagse-serve ang tool mo ng maliit na HTTP API sa isang local port; binabasa ng BakoshApp ang listahan mo ng mga aksyon at tumatawag ng isa sa tuwing may event sa TikTok o Kick na tumutugma sa trigger ng user. Anumang makokontrol mo mula sa code — smart lights, isang microcontroller, isang soundboard, ibang laro, ang sarili mong bot — ay maaaring tumugon sa live stream nang walang mod ng BakoshApp.
Paano Ito Konektado
- Nakikinig ang tool mo sa
http://127.0.0.1:8833. - Ikinokonekta ito ng user sa Mga Setting → Third-Party (host at port) at sinusuri ito gamit ang I-test ang koneksyon.
- Sa Mga Actions tab ng isang mod, ni-click ng user ang Magdagdag ng bago, pumili ng trigger, at sa Lahat ng Actions → External nag-configure ng Third-Party Action: pinupunan ng BakoshApp ang dalawang listahan ng mga kategorya at aksyon mo.
- Sa bawat event na tumutugma, tinatawagan ng BakoshApp ang tool mo, at ang code mo ang gumagawa ng trabaho.
Isang-direksyon lang ang koneksyon: tinatawagan ka ng BakoshApp, hindi kailanman kabaliktaran.
Port at Address
- 8833 ang default. Maaari itong baguhin ng user sa Mga Setting → Third-Party; sabihin sa mga user mo kung aling port ang ilalagay kung gumagamit ka ng iba.
- Hindi magagamit ang 8832: nakikinig doon ang BakoshApp mismo (ganito nahahanap ng TikFinity ang BakoshApp), at tinatanggihan ito ng setting.
- Walang authentication. Makinig sa
127.0.0.1, hindi sa0.0.0.0, para hindi maabot ang API mula sa network. - Palaging gumagamit ang BakoshApp ng plain HTTP.
Mga Endpoint
Dapat i-serve ng tool mo ang lahat ng apat. Ang bawat response ay JSON na may data member.
1. Impormasyon ng App
Kinikilala nito ang tool mo. Ipinapakita ito ng BakoshApp bilang "Nakakonekta sa Mock Tool 1.0 ng Bakosh" sa Mga Setting at sa action configurator.
GET /api/app/info
{ "data": { "name": "Mock Tool", "version": "1.0", "author": "Bakosh" } }2. Mga Kategorya
Ang unang listahan sa configurator.
GET /api/features/categories
{
"data": [
{ "categoryId": "smart_device_control", "categoryName": "Control Smart Devices" },
{ "categoryId": "serial_port_control", "categoryName": "Control Serial Port" }
]
}3. Mga Aksyon
Ang pangalawang listahan: ang mga aksyon ng isang kategorya. Ang categoryId ay 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" }
]
}Ipinapakita ng mga listahan ang mga item mo sa pagkakasunod-sunod na ibinabalik mo ang mga ito. Ang isang aksyon na na-save na ng user pero hindi mo na ibinabalik ay mananatili sa itaas ng listahan, para hindi ito basta na lang magbago nang tahimik.
Ang categoryId at actionId ang tanging ina-store ng BakoshApp para sa isang configured na aksyon. Panatilihin silang stable: ang pagpalit ng pangalan ng id ay sisira sa mga umiiral nang setup. Ang mga pangalan ay para sa display lang at maaaring magbago anumang oras.
4. Pag-execute
Tinatawag ito sa tuwing may tumutugmang event na nagpapatakbo ng aksyon.
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://…"
}
}Sumagot gamit ang walang laman na data array kapag tinanggap mo na ang request:
{ "data": [] }Timing
- Naghihintay ang BakoshApp ng hanggang 5 segundo para sa tatlong GET endpoint at 10 segundo para sa
exec. Ang isang request na nabigo o nag-time out ay hindi na inuulit. - Kung ang aksyon ay may Bilang na higit sa 1, tinatawagan ng BakoshApp ang
execng ganoong karaming beses, nang paisa-isa: naghihintay ito ng sagot mo, pagkatapos ng Interval ng row, tapos tumatawag muli. - Ang mga tawag para sa parehong row ay dumarating nang paisa-isa; maaaring tumawag sa iyo ang iba't ibang row nang magkakasabay (parallel).
Kaya sumagot nang mabilis at gawin ang mabagal na trabaho sa background — makakapagpadala ang mga viewer ng regalo nang mas mabilis kaysa sa galaw ng serial port.
Ang Context Object
Inilalarawan ng context ang event na nagpatakbo ng aksyon. Ang mga field lang na umiiral para sa event na iyon ang naroroon — suriin bago basahin.
| Field | Uri | Present |
|---|---|---|
triggerTypeId | number | palagi — tingnan sa ibaba |
eventType | string | palagi — gift, like, chat, follow, share, joined, subscribe, tikfinity o test |
source | string | palagi — eulerstream (TikTok), kick, tikfinity o test |
platform | string | Mga event ng TikTok at Kick — tiktok o kick |
username | string | palagi — ang handle ng viewer |
nickname | string | Mga event ng TikTok at Kick — ang display name |
userId | string | Mga event ng TikTok at Kick |
profilePictureUrl | string | kadalasan (nag-e-expire ang mga link ng avatar sa TikTok) |
comment | string | mga mensahe sa chat; sa Kick, pati na rin ang mensaheng nakalakip sa isang regalo |
giftName | string | mga regalo |
giftId | number | mga regalo sa TikTok |
repeatCount | number | mga regalo sa TikTok — bilang ng regalo sa streak; mga gifted subscription sa Kick — bilang ng tatanggap |
diamondCount | number | mga regalo — value sa Diamonds (TikTok) o presyo sa Kicks (Kick) |
coins | number | kapareho ng diamondCount |
likeCount | number | mga like |
subMonth | number | mga subscription |
Ang mga event na relayed mula sa TikFinity ay may dala lang na triggerTypeId (palaging 0), source, eventType at username.
Mga Uri ng Trigger
Ang triggerTypeId ay ang uri ng trigger na kina-configure ng user, kaya nakikilala ang pagkakaiba ng regalong pinili ayon sa pangalan at regalong tinutugma ayon sa value:
| Id | Trigger |
|---|---|
| 1 | Ibahagi |
| 3 | Min-Max (hanay ng value ng regalo) |
| 4 | Regalo |
| 6 | Sumali |
| 7 | Like |
| 9 | Follow |
| 10 | Subscribe / Super Fan |
| 11 | Chat |
| 0 | TikFinity, o kahit ano pa |
Ituring ang mga hindi kilalang id bilang 0; maaaring magdagdag pa ng iba.
Ang Button na Subukan
Tinatawagan ng Subukan sa row ng aksyon (at ng hotkey nito) ang exec gamit ang sample data: ang source at eventType ay test, ang triggerTypeId ay mula sa trigger ng row, ang viewer ay bakosh_app, at ang regalo ay isang Rose (giftId 5655). Walang platform.
Pag-uulat ng mga Problema
Magbalik ng message para ilarawan kung ano ang nagkamali:
{ "message": "Serial port COM3 is not available" }- Sa mga GET endpoint, anumang
messageay magiging dahilan para ituring ng BakoshApp ang sagot bilang error, kahit na HTTP 200 pa ito. - Sa
exec, isinusulat angmessagesa console at log file ng BakoshApp bilang warning. Hindi nakakakuha ang user ng pop-up.
Iginagalang din ang mga HTTP error status; kung walang message, ang status code lang ang ipinapakita sa log.
Paggamit Kasama ang TikFinity Din
Tumutugma ang interface na ito sa third-party interface ng TikFinity — parehong apat na path at field name — kaya isang tool lang ang makakapag-serve sa dalawa. Magkaiba ang ports: naghahanap ang TikFinity ng mga tool sa 8832, na inookupa ng BakoshApp habang tumatakbo ito, kaya bigyan ang BakoshApp ng ibang port.
Web app ang TikFinity at nangangailangan ito ng CORS headers (Access-Control-Allow-Origin: * at ang mga katulad nito) at sagot sa mga OPTIONS preflight request. Hindi kailangan ng BakoshApp ang mga ito, pero walang masamang mangyayari kung ipapadala mo pa rin ang mga ito. Nagpapadala ang BakoshApp ng mas maraming context field kaysa sa TikFinity — huwag pansinin ang mga hindi mo ginagamit.
Isang Kumpletong Gumaganang Tool
Walang dependencies — i-save bilang tool.mjs at patakbuhin ang 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}`));Pagsubok sa Tool Mo
- Simulan ang tool mo.
- Sa BakoshApp, buksan ang Mga Setting → Third-Party, suriin ang host at port, at i-click ang I-test ang koneksyon. Dapat mong makita ang pangalan, bersyon at author ng tool mo.
- Sa Mga Actions tab ng isang mod, i-click ang Magdagdag ng bago, pumili ng trigger at i-click ang Susunod. Sa Lahat ng Actions → External, i-click ang Configure sa tabi ng Third-Party Action, piliin ang kategorya at aksyon mo, at i-save.
- I-click ang Subukan sa bagong row — makakatanggap ang tool mo ng
execna mayeventType: "test". - Mag-live at suriin kung dumarating ang mga totoong event.
Kung sinabi ng configurator na "Hindi makakonekta! Suriin ang iyong integration.", suriin kung nakikinig ang tool sa 127.0.0.1, kung tumutugma ang port sa Mga Setting, at kung ibinabalik ng GET /api/app/info ang sagot nito sa loob ng data.