diff --git a/src/platforms/kick/modules/chat-attachments/chat-attachments.module.ts b/src/platforms/kick/modules/chat-attachments/chat-attachments.module.ts index 3df67b4e..1bb8519b 100644 --- a/src/platforms/kick/modules/chat-attachments/chat-attachments.module.ts +++ b/src/platforms/kick/modules/chat-attachments/chat-attachments.module.ts @@ -2,6 +2,7 @@ import KickModule from "$kick/kick.module.ts"; import { ImagePreview } from "$shared/components/image-preview/image-preview.component"; import { HttpClient } from "$shared/http/http-client.ts"; import type ChatAttachmentHandler from "$shared/module/chat-attachments/chat-attachment-handler.ts"; +import EmotesChatAttachmentHandler from "$shared/module/chat-attachments/emotes-chat-attachment-handler"; import ImageChatAttachmentHandler from "$shared/module/chat-attachments/image-chat-attachment-handler.ts"; import { ImageChatAttachmentConfig } from "$shared/module/chat-attachments/image-chat-attachment.config.ts"; import type { KickChatMessageEvent } from "$types/platforms/kick/kick.events.types.ts"; @@ -65,6 +66,7 @@ export default class ChatAttachmentsModule extends KickModule { private readonly chatAttachmentHandlers: ChatAttachmentHandler[] = [ new ImageChatAttachmentHandler(this.logger, this.imageAttachmentConfig), + new EmotesChatAttachmentHandler(this.logger), ]; private async handleMessage(message: KickChatMessageEvent) { @@ -126,11 +128,9 @@ export default class ChatAttachmentsModule extends KickModule { private async getAttachmentData(url: URL) { try { - const { response } = await this.httpClient.request(url.href, { - method: "HEAD", - responseType: "text", - }); - return { type: response.headers.get("Content-Type"), size: response.headers.get("Content-Length") }; + const { response } = await this.httpClient.request(url.href); + + return { type: response.headers.get("Content-Type"), size: "10" }; } catch (error) { this.logger.warn("Couldn't get attachment data", error); } diff --git a/src/shared/components/emote-preview/emote-preview.component.tsx b/src/shared/components/emote-preview/emote-preview.component.tsx new file mode 100644 index 00000000..6460db52 --- /dev/null +++ b/src/shared/components/emote-preview/emote-preview.component.tsx @@ -0,0 +1,16 @@ +import styled from "styled-components"; + +export const EmotePreview = (src?: string) => { + return ( + +
Test Test Test.
+
+ ); +}; + +const Wrapper = styled.div` + display: flex; + flex-direction: column; + align-items: center; + gap: 4px; +`; diff --git a/src/shared/module/chat-attachments/emotes-chat-attachment-handler.ts b/src/shared/module/chat-attachments/emotes-chat-attachment-handler.ts new file mode 100644 index 00000000..5f53a230 --- /dev/null +++ b/src/shared/module/chat-attachments/emotes-chat-attachment-handler.ts @@ -0,0 +1,77 @@ +import type { Logger } from "$shared/logger/logger.ts"; +import type { + BaseChatAttachmentData, + ChatAttachmentData, +} from "$types/shared/module/chat-attachment/chat-attachment.types.ts"; +import ChatAttachmentHandler from "./chat-attachment-handler"; + +export default class EmotesChatAttachmentHandler extends ChatAttachmentHandler { + constructor(protected readonly logger: Logger) { + super(logger); + } + + static readonly ALLOWED_HOSTS = ["7tv.app", "old.7tv.app"]; + + validate(baseData: BaseChatAttachmentData): boolean { + return EmotesChatAttachmentHandler.ALLOWED_HOSTS.some((host) => baseData.url.host === host); + } + + async applies(data: ChatAttachmentData): Promise { + return true; + // throw new Error("Not implemented"); + } + + parseUrl(url: URL): URL { + // INPUT: https://7tv.app/emotes/01F6MDFCSR0000WDA7ERT623YT + // OUTPUT: https://7tv.io/v3/emotes/01F6MDFCSR0000WDA7ERT623YT + // TODO: Parse only single emotes for now + + url.host = "7tv.io"; + url.pathname = `/v3${url.pathname}`; + + return url; + } + + async handle(data: ChatAttachmentData) { + // ! Temporary, as alternative for not supported emote data fetching + const emoteData = await (await fetch(data.url.href)).json(); + + const element = data.messageElement as HTMLLinkElement; + + element.classList.add("enhancer-emote-link"); + + const wrapper = document.createElement("div"); + element.replaceChildren(wrapper); + wrapper.style.backgroundColor = "grey"; + wrapper.style.borderRadius = "4px"; + wrapper.style.padding = "8px"; + wrapper.style.display = "flex"; + wrapper.style.flexDirection = "row"; + wrapper.style.gap = "8px"; + wrapper.style.textDecoration = "none"; + + const emotePreview = document.createElement("img"); + emotePreview.src = `https://cdn.7tv.app/emote/${emoteData.id}/${emoteData.host.files[0].name}`; + emotePreview.style.width = "48px"; + emotePreview.style.height = "48px"; + wrapper.append(emotePreview); + + const emoteDataWrapper = document.createElement("div"); + emoteDataWrapper.style.display = "flex"; + emoteDataWrapper.style.flexDirection = "column"; + emoteDataWrapper.style.justifyContent = "space-between"; + wrapper.append(emoteDataWrapper); + + const emoteName = document.createElement("span"); + emoteName.textContent = emoteData.name || "Emote Name"; + emoteName.style.color = "white"; + emoteName.style.textDecoration = "none"; + emoteDataWrapper.append(emoteName); + + const emoteAuthor = document.createElement("span"); + emoteAuthor.textContent = `Created by ${emoteData.owner.username || "unknown"}`; + emoteAuthor.style.color = "white"; + emoteAuthor.style.textDecoration = "none"; + emoteDataWrapper.append(emoteAuthor); + } +}