const kickUserName = getURLParam("kickUserName", false);
const showKickMessages = getURLParam("showKickMessages", true);
const showKickFollows = getURLParam("showKickFollows", true);
const showKickSubs = getURLParam("showKickSubs", true);
const showKickGiftedSubs = getURLParam("showKickGiftedSubs", true);
const showKickMassGiftedSubs = getURLParam("showKickMassGiftedSubs", true);
const showKickRaids = getURLParam("showKickRaids", true);
const showKickViewers = getURLParam("showKickViewers", true);
const kickAvatars = new Map();
const kick7TVEmojis = new Map();
if (showKickViewers == false) { document.querySelector('#statistics #kick').style.display = 'none'; }
const kickWebSocket = new WebSocket(
`wss://ws-us2.pusher.com/app/32cbd69e4b950bf97679?protocol=7&client=js&version=8.4.0-rc2&flash=false`
);
kickWebSocket.onerror = (error) => {
console.error("Kick WebSocket Error: " + error);
};
kickWebSocket.onopen = () => {
kickGetUserInfo(kickUserName)
.then((userInfo) => {
console.log('Got Kick User Info', userInfo);
(async () => {
const kick7TVEmotes = await get7TVEmotes(userInfo.user_id);
if (kick7TVEmotes != null) {
console.debug("Getting all Kick's 7TV Emojis + Globals", kick7TVEmotes);
kick7TVEmotes.forEach(emote => {
kick7TVEmojis.set(emote.name, emote.url);
});
}
})();
kickWebSocket.send(
JSON.stringify({
event: "pusher:subscribe",
data: {
auth: null,
channel: `chatrooms.${userInfo.chatroom.id}.v2`
},
})
);
kickWebSocket.send(
JSON.stringify({
event: "pusher:subscribe",
data: {
auth: null,
channel: `channel.${userInfo.chatroom.channel_id}`
},
})
);
setInterval(() => {
kickWebSocket.send(
JSON.stringify({
event: "pusher:ping",
data: {},
})
);
}, 60000);
kickUpdateStatistics(userInfo);
setInterval(() => {
kickGetUserInfo(kickUserName)
.then((data) =>{
kickUpdateStatistics(data);
});
}, 15000);
});
};
kickWebSocket.onmessage = async ({ data }) => {
const parsed = JSON.parse(data);
const json = JSON.parse(parsed.data);
if (!parsed.event.includes("pusher")) {
switch (parsed.event) {
case "App\\Events\\ChatMessageEvent":
console.debug('Kick Chat', json);
kickChatMessage(json);
break;
case "App\\Events\\MessageDeletedEvent":
kickChatMessageDeleted(json);
break;
case "App\\Events\\UserBannedEvent":
kickUserBanned(json);
break;
case "App\\Events\\ChatroomClearEvent":
kickChatClearMessages()
break;
default:
console.debug('Kick Event From WebSocket', parsed.event, json);
}
}
};
streamerBotClient.on('General.Custom', (response) => {
if (response.data.platform === 'Kick') {
const data = response.data.data;
switch (data.triggerCustomCodeEventName) {
case "kickFollow" :
console.debug('Kick Follow', data);
kickFollowMessage(data);
break;
case "kickSub" :
console.debug('Kick Sub', data);
kickSubMessage(data);
break;
case "kickGift" :
console.debug('Kick Sub Gift', data);
kickGiftMessage(data);
break;
case "kickGifts" :
console.debug('Kick Mass Sub Gift', data);
kickGiftSubsMessage(data);
break;
case "kickIncomingRaid" :
console.debug('Kick Raid', data);
kickRaidMessage(data);
break;
default:
//console.debug('Kick Event', response.data);
}
}
});
async function kickChatMessage(data) {
if (showKickMessages == false) return;
if (ignoreUserList.includes(data.sender.username.toLowerCase())) return;
if (data.content.startsWith("!") && excludeCommands == true) return;
const {
id: messageId,
type,
content: text,
sender: {
id: userID,
slug: userSlug,
username: userName,
identity: {
color,
badges: badgesToParse
}
}
} = data;
const [avatar, message, badges] = await Promise.all([
getKickAvatar(userSlug),
getKickEmotes(text),
getKickBadges(badgesToParse),
]);
const replyHTML = (type == "reply" ?
`
${data.metadata.original_sender.username}: ${await getKickEmotes(data.metadata.original_message.content)}
` : '');
const messageData = {
classes: '',
avatar,
badges,
userName,
color,
message,
shared: '',
reply: replyHTML,
};
addMessageToChat(userSlug, messageId, 'kick', messageData);
}
async function kickFollowMessage(data) {
if (showKickFollows == false) return;
const {
userName : userID,
user : userName
} = data;
const messageID = createRandomString(40);
const [avatar, message] = await Promise.all([
'',
currentLang.kick.follow(),
]);
const classes = 'follow';
const messageData = {
classes: classes,
avatar,
badges: '',
userName,
color: '#FFF',
message,
reply: '',
};
addEventToChat(userID, messageID, 'kick', messageData);
}
async function kickSubMessage(data) {
if (showKickSubs == false) return;
const {
userName: userID,
user: userName,
tier,
cumulative
} = data;
const messageID = createRandomString(40);
const [avatar, message] = await Promise.all([
'',
currentLang.kick.sub({
months : cumulative,
tier : tier
})
]);
const classes = 'sub';
const messageData = {
classes: classes,
avatar,
badges: '',
userName,
color: '#FFF',
message,
reply: '',
};
addEventToChat(userID, messageID, 'kick', messageData);
}
async function kickGiftMessage(data) {
if (showKickSubs == false || showKickGiftedSubs == false) return;
const {
user: userName,
userName: userID,
recipientUser: recipientName,
tier,
totalSubsGifted
} = data;
const messageID = createRandomString(40);
const [avatar, message] = await Promise.all([
'',
currentLang.kick.gifted({
gifted : recipientName,
tier : tier,
total : totalSubsGifted
})
]);
const classes = 'sub';
const messageData = {
classes: classes,
avatar,
badges: '',
userName,
color: '#FFF',
message,
reply: '',
};
addEventToChat(userID, messageID, 'kick', messageData);
}
async function kickGiftSubsMessage(data) {
if (showKickSubs == false || showKickMassGiftedSubs == false) return;
const {
user: userName,
userName: userID,
tier,
gifts
} = data;
const messageID = createRandomString(40);
const [avatar, message] = await Promise.all([
'',
currentLang.kick.giftedbomb({
count : gifts,
tier : tier
})
]);
const classes = 'sub';
const messageData = {
classes: classes,
avatar,
badges: '',
userName,
color: '#FFF',
message,
reply: '',
};
addEventToChat(userID, messageID, 'kick', messageData);
}
async function kickRaidMessage(data) {
if (showKickRaids == false) return;
const {
user: userName,
viewers
} = data;
const userID = userName.toLowerCase();
const messageID = createRandomString(40);
const [avatar, message] = await Promise.all([
'',
currentLang.kick.raid({ viewers : viewers })
]);
const classes = 'raid';
const messageData = {
classes: classes,
avatar,
badges: '',
userName,
color: '#FFF',
message,
reply: '',
};
addEventToChat(userID, messageID, 'kick', messageData);
}
async function kickChatMessageDeleted(data) {
document.getElementById(data.message.id)?.remove();
}
async function kickUserBanned(data) {
chatContainer.querySelectorAll(`[data-user="${data.user.slug}"]`).forEach(element => {
element.remove();
});
}
async function kickChatClearMessages() {
chatContainer.querySelectorAll(`.kick`).forEach(element => {
element.remove();
});
}
async function kickUpdateStatistics(data) {
if (showPlatformStatistics == false || showKickViewers == false) return;
if (data.livestream == null) { }
else {
const viewers = DOMPurify.sanitize(data.livestream.viewer_count);
document.querySelector('#statistics #kick .viewers span').textContent = formatNumber(viewers);
}
}
async function kickGetUserInfo(user) {
const response = await fetch( `https://kick.com/api/v2/channels/${user}` );
if (response.status === 404) {
console.error("Kick user was not found!");
return 404;
}
else {
const data = await response.json();
return data;
}
}
async function getKickAvatar(user) {
if (showAvatar == true) {
if (kickAvatars.has(user)) {
console.debug(`Kick avatar found for ${user}!`);
return kickAvatars.get(user);
}
else {
console.debug(`Kick avatar not found for ${user}! Trying to get it...`);
const response = await kickGetUserInfo(user);
var newavatar = '';
if (response == 404) {
newavatar = 'https://kick.com/img/default-profile-pictures/default2.jpeg';
}
else {
if (response.user.profile_pic == null) {
newavatar = 'https://kick.com/img/default-profile-pictures/default2.jpeg';
}
else {
newavatar = response.user.profile_pic;
newavatar = newavatar.replace(/fullsize(?=\.webp)/, "medium");
}
kickAvatars.set(user, newavatar);
}
return newavatar;
}
}
}
async function getKickEmotes(text) {
var message = await parseKickEmojis(text);
message = await parseKick7TVEmotes(message);
return message;
}
async function parseKickEmojis(content) {
const message = content;
const messagewithemotes = message.replace(/\[emote:(\d+):([^\]]+)\]/g, (_, id, name) => {
return `
`;
});
return messagewithemotes;
}
async function parseKick7TVEmotes(text) {
const words = text.split(/\s+/);
const parsedWords = words.map(word => {
const clean = word.replace(/[^\w]/g, ''); // remove pontuação para comparar
if (kick7TVEmojis.has(clean)) {
const url = kick7TVEmojis.get(clean);
return word.replace(clean, `
`);
}
return word;
});
return parsedWords.join(' ');
}
async function get7TVEmotes(userid) {
const userSet = await fetch(`https://7tv.io/v3/users/kick/${userid}`);
if (userSet.status === 404) {
console.debug("7TV Profile based on this Kick user was not found");
return null;
}
const userEmojis = await userSet.json();
const gettingAllKick7TVEmotes = userEmojis?.emote_set?.emotes?.map(emote => ({
name: emote.name,
id: emote.id,
url: `https://cdn.7tv.app/emote/${emote.id}/1x.webp`
})) || [];
const globalSet = await fetch(`https://7tv.io/v3/emote-sets/global`);
const globalEmojis = await globalSet.json();
const gettingAllGlobal7TVEmotes = globalEmojis?.emotes?.map(emote => ({
name: emote.name,
id: emote.id,
url: `https://cdn.7tv.app/emote/${emote.id}/1x.webp`
})) || [];
const SevenTVEmotesFusion = [...gettingAllKick7TVEmotes, ...gettingAllGlobal7TVEmotes];
return SevenTVEmotesFusion;
}
async function getKickBadges(badges) {
const badgesArray = [];
badges.forEach(badge => {
switch (badge.type) {
case "broadcaster":
badgesArray.push('');
break;
case "sidekick":
badgesArray.push('');
break;
case "moderator":
badgesArray.push('');
break;
case "vip":
badgesArray.push('');
break;
case "sub_gifter":
badgesArray.push('');
break;
case "og":
badgesArray.push('');
break;
case "founder":
badgesArray.push('');
break;
case "subscriber":
badgesArray.push('');
break;
case "verified":
badgesArray.push('');
break;
}
});
return badgesArray.join(' ');
}