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'; } if (kickUserName) { 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); } } }; } else { console.debug('Kick User not set in ChatRD'); } 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}"]:not(.event)`).forEach(element => { element.remove(); }); } async function kickChatClearMessages() { chatContainer.querySelectorAll(`.kick:not(.event)`).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 `${name}`; }); 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, `${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(' '); }