diff --git a/horizontal-chat/icons/badges/kick-kicks.svg b/horizontal-chat/icons/badges/kick-kicks.svg new file mode 100644 index 0000000..3f5a142 --- /dev/null +++ b/horizontal-chat/icons/badges/kick-kicks.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/horizontal-chat/script.js b/horizontal-chat/script.js index 2cb44b7..f932541 100644 --- a/horizontal-chat/script.js +++ b/horizontal-chat/script.js @@ -58,6 +58,7 @@ const showKickMessages = GetBooleanParam("showKickMessages", true); const showKickSubs = GetBooleanParam("showKickSubs", true); const showKickChannelPointRedemptions = GetBooleanParam("showKickChannelPointRedemptions", true); const showKickHosts = GetBooleanParam("showKickHosts", true); +const showKickGifts = GetBooleanParam("showKickGifts", true); const showYouTubeMessages = GetBooleanParam("showYouTubeMessages", true); const showYouTubeSuperChats = GetBooleanParam("showYouTubeSuperChats", true); @@ -301,7 +302,9 @@ async function KickConnect() { return; // Channel to subscribe to (you'll need the correct channel name here) - const chatroomId = await GetKickChatroomId(kickUsername); + const kickIds = await GetKickIds(kickUsername); + const chatroomId = kickIds.chatroomId; + const channelId = kickIds.channelId; // Cache subscriber badges kickSubBadges = await GetKickSubBadges(kickUsername); @@ -334,6 +337,7 @@ async function KickConnect() { websocket.send(JSON.stringify({ event: 'pusher:subscribe', data: { channel: `chatrooms.${chatroomId}` } })); websocket.send(JSON.stringify({ event: 'pusher:subscribe', data: { channel: `chatrooms.${chatroomId}.v2` } })); websocket.send(JSON.stringify({ event: 'pusher:subscribe', data: { channel: `predictions-channel-${chatroomId}` } })); + websocket.send(JSON.stringify({ event: 'pusher:subscribe', data: { channel: `channel_${channelId}` } })); console.log(`[Pusher] Sent subscription request to channel: ${chatroomId}`); } @@ -365,6 +369,9 @@ async function KickConnect() { case 'UserBannedEvent': KickUserBanned(eventArgs); break; + case 'KicksGifted': + KickKicksGifted(eventArgs); + break; } } catch (error) { @@ -1425,6 +1432,18 @@ function KickUserBanned(data) { }); } +function KickKicksGifted(data) { + if (!showKickGifts) + return; + + const kicksImg = ``; + const giftImg = ``; + + const message = ` ${giftImg} ${data.sender.username} sent ${data.gift.name} ${kicksImg} ${data.gift.amount}`; + + ShowAlert(message, 'kick'); +} + async function TikTokChat(data) { if (!showTikTokMessages) return; @@ -1863,25 +1882,25 @@ function EscapeRegExp(string) { return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string } -async function GetKickChatroomId(username) { - const url = `https://kick.com/api/v2/channels/${username}`; +async function GetKickIds(username) { + const url = `https://kick.com/api/v2/channels/${username}`; - try { - const response = await fetch(url); - if (!response.ok) { - throw new Error(`HTTP error ${response.status}`); - } + try { + const response = await fetch(url); + if (!response.ok) { + throw new Error(`HTTP error ${response.status}`); + } - const data = await response.json(); - if (data.chatroom && data.chatroom.id) { - return data.chatroom.id; - } else { - throw new Error("Chatroom ID not found in response."); - } - } catch (error) { - console.error("Failed to fetch chatroom ID:", error.message); - return null; - } + const data = await response.json(); + if (data.chatroom && data.chatroom.id) { + return { chatroomId: data.chatroom.id, channelId: data.chatroom.channel_id }; + } else { + throw new Error("Chatroom ID not found in response."); + } + } catch (error) { + console.error("Failed to fetch chatroom ID:", error.message); + return null; + } } async function GetKickSubBadges(username) { diff --git a/horizontal-chat/settings/settings.json b/horizontal-chat/settings/settings.json index 2891d09..0222140 100644 --- a/horizontal-chat/settings/settings.json +++ b/horizontal-chat/settings/settings.json @@ -255,6 +255,14 @@ "defaultValue": true, "group": "Which Kick messages do you want to see?" }, + { + "id": "showKickGifts", + "label": "Gifts", + "description": "", + "type": "checkbox", + "defaultValue": true, + "group": "Which Kick messages do you want to see?" + }, { "id": "enableTikTokSupport", "label": "Enable TikTok Support", diff --git a/horizontal-chat/style.css b/horizontal-chat/style.css index baf5c59..a7a0419 100644 --- a/horizontal-chat/style.css +++ b/horizontal-chat/style.css @@ -76,6 +76,10 @@ html { /* background-color: red; */ } +#alertBoxContent img { + height: 1.2em; +} + #background { position: absolute; bottom: 0; diff --git a/multichat-overlay/icons/badges/kick-kicks.svg b/multichat-overlay/icons/badges/kick-kicks.svg new file mode 100644 index 0000000..3f5a142 --- /dev/null +++ b/multichat-overlay/icons/badges/kick-kicks.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/multichat-overlay/index.html b/multichat-overlay/index.html index de32944..00a06c4 100644 --- a/multichat-overlay/index.html +++ b/multichat-overlay/index.html @@ -66,7 +66,7 @@ + + \ No newline at end of file diff --git a/multichat-overlay/script.js b/multichat-overlay/script.js index 6779df8..035dfa7 100644 --- a/multichat-overlay/script.js +++ b/multichat-overlay/script.js @@ -61,6 +61,7 @@ const showKickMessages = GetBooleanParam("showKickMessages", true); const showKickSubs = GetBooleanParam("showKickSubs", true); const showKickChannelPointRedemptions = GetBooleanParam("showKickChannelPointRedemptions", true); const showKickHosts = GetBooleanParam("showKickHosts", true); +const showKickGifts = GetBooleanParam("showKickGifts", true); const showYouTubeMessages = GetBooleanParam("showYouTubeMessages", true); const showYouTubeSuperChats = GetBooleanParam("showYouTubeSuperChats", true); @@ -322,6 +323,11 @@ client.on('Fourthwall.GiftDrawEnded', (response) => { FourthwallGiftDrawEnded(response.data); }) +client.on('Fourthwall.GiftDrawEnded', (response) => { + console.debug(response.data); + FourthwallGiftDrawEnded(response.data); +}) + /////////////////////////// @@ -334,7 +340,9 @@ async function KickConnect() { return; // Channel to subscribe to (you'll need the correct channel name here) - const chatroomId = await GetKickChatroomId(kickUsername); + const kickIds = await GetKickIds(kickUsername); + const chatroomId = kickIds.chatroomId; + const channelId = kickIds.channelId; // Cache subscriber badges kickSubBadges = await GetKickSubBadges(kickUsername); @@ -367,6 +375,7 @@ async function KickConnect() { websocket.send(JSON.stringify({ event: 'pusher:subscribe', data: { channel: `chatrooms.${chatroomId}` } })); websocket.send(JSON.stringify({ event: 'pusher:subscribe', data: { channel: `chatrooms.${chatroomId}.v2` } })); websocket.send(JSON.stringify({ event: 'pusher:subscribe', data: { channel: `predictions-channel-${chatroomId}` } })); + websocket.send(JSON.stringify({ event: 'pusher:subscribe', data: { channel: `channel_${channelId}` } })); console.log(`[Pusher] Sent subscription request to channel: ${chatroomId}`); } @@ -398,6 +407,9 @@ async function KickConnect() { case 'UserBannedEvent': KickUserBanned(eventArgs); break; + case 'KicksGifted': + KickKicksGifted(eventArgs); + break; } } catch (error) { @@ -2518,6 +2530,35 @@ function KickMessageDeleted(data) { }, 500); } +async function KickKicksGifted(data) { + if (!showKickGifts) + return; + + // Get a reference to the template + const template = document.getElementById('kick-gift-template'); + + // Create a new instance of the template + const instance = template.content.cloneNode(true); + + // Get divs + const avatarImg = instance.querySelector('.kick-gift-avatar'); + const usernameSpan = instance.querySelector('#kick-gift-username'); + const giftNameSpan = instance.querySelector('#kick-gift-name'); + const stickerImg = instance.querySelector('.kick-gift-sticker'); + const amountDiv = instance.querySelector('#kick-gift-amount'); + const messageDiv = instance.querySelector('#kick-gift-message'); + + avatarImg.src = await GetAvatar(data.sender.username.replace('_', '-'), 'kick'); // Set the card header + usernameSpan.innerText = data.sender.username; // Set the username + usernameSpan.style.color = data.sender.username_color; + giftNameSpan.innerText = data.gift.name; // Set the gift name + stickerImg.src = `https://files.kick.com/kicks/gifts/${data.gift.gift_id.replace('_', '-')}.webp`; // Set the sticker image URL + amountDiv.innerText = data.gift.amount; // Set the number of gifts sent + messageDiv.innerText = data.message // Set the message + + AddMessageItem(instance, null, 'kick', data.senderId); +} + function KickUserBanned(data) { const messageList = document.getElementById("messageList"); @@ -3188,25 +3229,25 @@ function EscapeRegExp(string) { return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string } -async function GetKickChatroomId(username) { - const url = `https://kick.com/api/v2/channels/${username}`; +async function GetKickIds(username) { + const url = `https://kick.com/api/v2/channels/${username}`; - try { - const response = await fetch(url); - if (!response.ok) { - throw new Error(`HTTP error ${response.status}`); - } + try { + const response = await fetch(url); + if (!response.ok) { + throw new Error(`HTTP error ${response.status}`); + } - const data = await response.json(); - if (data.chatroom && data.chatroom.id) { - return data.chatroom.id; - } else { - throw new Error("Chatroom ID not found in response."); - } - } catch (error) { - console.error("Failed to fetch chatroom ID:", error.message); - return null; - } + const data = await response.json(); + if (data.chatroom && data.chatroom.id) { + return { chatroomId: data.chatroom.id, channelId: data.chatroom.channel_id }; + } else { + throw new Error("Chatroom ID not found in response."); + } + } catch (error) { + console.error("Failed to fetch chatroom ID:", error.message); + return null; + } } async function GetKickSubBadges(username) { diff --git a/multichat-overlay/settings/settings.json b/multichat-overlay/settings/settings.json index d1383cc..dbf67a4 100644 --- a/multichat-overlay/settings/settings.json +++ b/multichat-overlay/settings/settings.json @@ -376,6 +376,14 @@ "defaultValue": true, "group": "Which Kick messages do you want to see?" }, + { + "id": "showKickGifts", + "label": "Gifts", + "description": "", + "type": "checkbox", + "defaultValue": true, + "group": "Which Kick messages do you want to see?" + }, { "id": "enableTikTokSupport", "label": "Enable TikTok Support", diff --git a/multichat-overlay/style.css b/multichat-overlay/style.css index cd048e3..2736e7d 100644 --- a/multichat-overlay/style.css +++ b/multichat-overlay/style.css @@ -224,17 +224,18 @@ li { transform: translate(0px, 0.25em); } +.kick-gift, .tiktok-gift { display: flex; flex-direction: row; align-items: center; gap: 1em; - padding: 0.5em 1em; + padding: 0.5em; border-radius: var(--border-radius); max-width: 100%; - background: linear-gradient(#262626BF, #000000BF) !important; } +.kick-gift-avatar, .tiktok-gift-avatar { height: 3em; margin: 1px; @@ -243,17 +244,37 @@ li { flex-shrink: 0; } +.kick-gift-contents, .tiktok-gift-message { flex-grow: 1; - white-space: nowrap; /* keeps text in a single line */ - overflow: hidden; /* hides overflowed content */ - text-overflow: ellipsis; /* adds the "..." at the end */ + /* white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; */ + gap: 1em; +} + +.kick-gift-contents { + /* text-align: center; */ +} + +#kick-gift-message { + font-size: 0.9em; +} + +.kick-gift-sticker, +.tiktok-gift-sticker { + flex-shrink: 0; + justify-content: flex-end; + + filter: drop-shadow(5px 5px 5px #00000060); } .tiktok-gift-sticker { height: 2.5em; - flex-shrink: 0; - justify-content: flex-end; +} + +.kick-gift-sticker { + height: 5em; } #tiktok-gift-repeat-count { @@ -292,7 +313,7 @@ li { } .kick { - background: linear-gradient(#53fc18, #005600) !important; + background: linear-gradient(#32b602, #005600) !important; } .streamlabs { diff --git a/multistream-alerts/icons/badges/kick-kicks.svg b/multistream-alerts/icons/badges/kick-kicks.svg new file mode 100644 index 0000000..3f5a142 --- /dev/null +++ b/multistream-alerts/icons/badges/kick-kicks.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/multistream-alerts/script.js b/multistream-alerts/script.js index 30eacaf..ca29eae 100644 --- a/multistream-alerts/script.js +++ b/multistream-alerts/script.js @@ -77,6 +77,8 @@ const showKickChannelPointRedemptions = GetBooleanParam("showKickChannelPointRed const kickChannelPointRedemptionAction = urlParams.get("kickChannelPointRedemptionAction") || ""; const showKickHosts = GetBooleanParam("showKickHosts", true); const kickHostAction = urlParams.get("kickHostAction") || ""; +const showKickGifts = GetBooleanParam("showKickGifts", true); +const kickGiftAction = urlParams.get("kickGiftAction") || ""; // Which YouTube alerts do you want to see? const showYouTubeSuperChats = GetBooleanParam("showYouTubeSuperChats", true); @@ -315,7 +317,9 @@ async function KickConnect() { return; // Channel to subscribe to (you'll need the correct channel name here) - const chatroomId = await GetKickChatroomId(kickUsername); + const kickIds = await GetKickIds(kickUsername); + const chatroomId = kickIds.chatroomId; + const channelId = kickIds.channelId; // Cache subscriber badges kickSubBadges = await GetKickSubBadges(kickUsername); @@ -348,6 +352,7 @@ async function KickConnect() { websocket.send(JSON.stringify({ event: 'pusher:subscribe', data: { channel: `chatrooms.${chatroomId}` } })); websocket.send(JSON.stringify({ event: 'pusher:subscribe', data: { channel: `chatrooms.${chatroomId}.v2` } })); websocket.send(JSON.stringify({ event: 'pusher:subscribe', data: { channel: `predictions-channel-${chatroomId}` } })); + websocket.send(JSON.stringify({ event: 'pusher:subscribe', data: { channel: `channel_${channelId}` } })); console.log(`[Pusher] Sent subscription request to channel: ${chatroomId}`); } @@ -370,6 +375,9 @@ async function KickConnect() { case 'StreamHostEvent': KickStreamHost(eventArgs); break; + case 'KicksGifted': + KickKicksGifted(eventArgs); + break; } } catch (error) { @@ -1365,6 +1373,33 @@ async function KickStreamHost(data) { ); } +async function KickKicksGifted(data) { + if (!showKickGifts) + return; + + // Set the text + const username = data.sender.username; + const tiktokIcon = ``; + // const giftImg = ``; + const kickKicksIcon = ``; + + // Render avatars + // const avatarURL = await GetAvatar(data.sender.username.replace('_', '-'), 'kick'); + const avatarURL = `https://files.kick.com/kicks/gifts/${data.gift.gift_id.replace('_', '-')}.webp`; + + UpdateAlertBox( + 'kick', + avatarURL, + `${username}`, + `sent ${kickKicksIcon} ${data.gift.amount}`, + '', + username, + data.message, + kickGiftAction, + data + ); +} + async function TikTokGift(data) { if (!showTikTokGifts) return; @@ -1710,25 +1745,25 @@ function UpdateAlertBox(platform, avatarURL, headerText, descriptionText, attrib } -async function GetKickChatroomId(username) { - const url = `https://kick.com/api/v2/channels/${username}`; +async function GetKickIds(username) { + const url = `https://kick.com/api/v2/channels/${username}`; - try { - const response = await fetch(url); - if (!response.ok) { - throw new Error(`HTTP error ${response.status}`); - } + try { + const response = await fetch(url); + if (!response.ok) { + throw new Error(`HTTP error ${response.status}`); + } - const data = await response.json(); - if (data.chatroom && data.chatroom.id) { - return data.chatroom.id; - } else { - throw new Error("Chatroom ID not found in response."); - } - } catch (error) { - console.error("Failed to fetch chatroom ID:", error.message); - return null; - } + const data = await response.json(); + if (data.chatroom && data.chatroom.id) { + return { chatroomId: data.chatroom.id, channelId: data.chatroom.channel_id }; + } else { + throw new Error("Chatroom ID not found in response."); + } + } catch (error) { + console.error("Failed to fetch chatroom ID:", error.message); + return null; + } } async function GetKickSubBadges(username) { diff --git a/multistream-alerts/settings/settings.json b/multistream-alerts/settings/settings.json index 87cb412..89768e0 100644 --- a/multistream-alerts/settings/settings.json +++ b/multistream-alerts/settings/settings.json @@ -422,6 +422,23 @@ "showIf": "showKickHosts", "group": "Which Kick alerts do you want to see?" }, + { + "id": "showKickGifts", + "label": "Gifts", + "description": "", + "type": "checkbox", + "defaultValue": true, + "group": "Which Kick alerts do you want to see?" + }, + { + "id": "kickGiftAction", + "label": "", + "description": "Also run this Streamer.bot Action", + "type": "sb-actions", + "defaultValue": "", + "showIf": "showKickGifts", + "group": "Which Kick alerts do you want to see?" + }, { "id": "enableTikTokSupport", "label": "Enable TikTok Support",