-
-
Notifications
You must be signed in to change notification settings - Fork 364
Description
Hello,
I'm using the tiktok-live-connector library to listen to chat messages and gifts from TikTok live streams. However, I noticed that some chat messages visible in the TikTok live chat are not received or logged by the connector.
I tested with the username edwardshow9 and implemented the following code (see below). While gifts and some messages are received, many chat messages that are clearly visible on the live stream do not come through.
I suspect this might be related to:
TikTok filtering or limiting messages for third-party clients
Some internal API limitations or protocol changes
Possibly account restrictions (like age) or authorization issues
Could you please help me understand why some messages are missing and how to reliably get all chat messages?
Thank you in advance!
const WebSocket = require('ws');
const { WebcastPushConnection } = require('tiktok-live-connector');
const fs = require('fs');
const path = require('path');
const { normalizeNick, verbalizeNick, numberToWords } = require('./normalizer');
const giftGrammar = require('./giftGrammar');
const tiktokUsername = 'edwardshow9';
const minichatWS = new WebSocket('ws://localhost:4848/Chat');
const giftsMerged = JSON.parse(
fs.readFileSync(path.join(__dirname, 'gifts_merged.json'), 'utf8')
);
function getGiftTranslation(giftName) {
const entry = giftsMerged.find(g => g.giftName_en === giftName);
return entry ? entry.giftName_ru : giftName;
}
function declineGift(giftName, count) {
const forms = giftGrammar[giftName];
if (!forms) return ${count} ${giftName}
;
const n = count % 100;
const n1 = count % 10;
let wordForm;
if (n > 10 && n < 20) {
wordForm = forms[3];
} else if (n1 === 1) {
wordForm = forms[1];
} else if (n1 >= 2 && n1 <= 4) {
wordForm = forms[2];
} else {
wordForm = forms[3];
}
return ${count} ${wordForm}
;
}
function verbalDeclineGift(giftName, count) {
const forms = giftGrammar[giftName];
if (!forms) return ${numberToWords(count)} ${giftName}
;
const n = count % 100;
const n1 = count % 10;
let wordForm;
if (n > 10 && n < 20) {
wordForm = forms[3];
} else if (n1 === 1) {
wordForm = forms[1];
} else if (n1 >= 2 && n1 <= 4) {
wordForm = forms[2];
} else {
wordForm = forms[3];
}
const numberWord = count === 1 ? forms[0] : numberToWords(count);
return ${numberWord} ${wordForm}
;
}
minichatWS.on('open', () => {
console.log('✅ Connected to Minichat');
const tiktok = new WebcastPushConnection(tiktokUsername);
let isConnected = false;
let ignoreUntil = 0;
const giftBuffer = new Map();
const recentGifts = [];
function flushGiftBuffer() {
const now = Date.now();
for (const [key, gift] of giftBuffer.entries()) {
if (now - gift.lastUpdated >= 1500) {
const duplicate = recentGifts.find(g =>
g.userId === gift.userId &&
g.giftId === gift.giftId &&
g.count === gift.count &&
now - g.time < 20000
);
if (duplicate) {
giftBuffer.delete(key);
continue;
}
recentGifts.push({
userId: gift.userId,
giftId: gift.giftId,
count: gift.count,
time: now
});
if (recentGifts.length > 100) recentGifts.shift();
const ruGift = getGiftTranslation(gift.giftName);
const readableGift = declineGift(ruGift, gift.count);
const verbalGift = verbalDeclineGift(ruGift, gift.count);
const voiceLine = `${verbalizeNick(gift.nickname)} дарит ${verbalGift}`;
const msg = {
Type: "Live",
Data: {
ShowInChat: false,
Type: "Donation",
CurrencyType: "TikTok",
Currency: "TikTok",
Tag: 101,
Service: "MiniChat",
UserID: gift.userId,
UserName: "Подарок",
Meta: { Login: gift.uniqueId },
Message: `${gift.nickname} дарит ${readableGift}`,
VoiceText: voiceLine
}
};
minichatWS.send(JSON.stringify(msg));
console.log(`🎁 Donation from ${gift.nickname}: ${readableGift}`);
giftBuffer.delete(key);
}
}
}
setInterval(flushGiftBuffer, 1000);
tiktok.connect()
.then(() => {
console.log(📡 Connected to TikTok @${tiktokUsername}
);
isConnected = true;
ignoreUntil = Date.now() + 3000;
})
.catch(err => console.error('❌ TikTok error:', err));
tiktok.on('chat', data => {
if (!isConnected || minichatWS.readyState !== WebSocket.OPEN) return;
if (Date.now() < ignoreUntil) return;
const comment = data.comment?.trim();
if (!comment) return;
const rawNick = data.nickname || data.uniqueId || '';
const msg = {
Type: "Message",
Data: {
ShowInChat: true,
UserID: data.userId?.toString() || "0",
UserName: rawNick,
Message: comment,
Service: "MiniChat"
}
};
try {
minichatWS.send(JSON.stringify(msg));
console.log(`💬 Chat: ${rawNick}: ${comment}`);
} catch (err) {
console.error('❌ Error sending message to Minichat:', err.message);
}
});
tiktok.on('gift', data => {
if (minichatWS.readyState !== WebSocket.OPEN) return;
const userId = data.userId?.toString() || "0";
const giftId = data.giftId?.toString() || "0";
const key = `${userId}_${giftId}`;
const nickname = data.nickname || data.uniqueId || '';
const giftName = data.giftName || "gift";
const giftCount = data.repeatCount || 1;
if (!giftBuffer.has(key)) {
giftBuffer.set(key, {
userId,
uniqueId: data.uniqueId,
giftId,
nickname,
giftName,
count: giftCount,
lastUpdated: Date.now()
});
} else {
const entry = giftBuffer.get(key);
entry.count = giftCount;
entry.lastUpdated = Date.now();
}
});
});
minichatWS.on('error', err => {
console.error('❌ Minichat WebSocket error:', err.message);
});
minichatWS.on('close', () => {
console.log('
});