From e88dcf0eafa20ad474be8f5b705d6f0db07b5267 Mon Sep 17 00:00:00 2001 From: Merith <merith@merith.xyz> Date: Wed, 26 Feb 2025 15:09:58 -0800 Subject: [PATCH] more work --- cmd/m3r1-chat/chat.html | 47 ----------------- cmd/m3r1-chat/main.go | 63 ----------------------- main.go | 76 ++++++++++++++++++++++++++++ static/overlay.html | 108 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 184 insertions(+), 110 deletions(-) delete mode 100644 cmd/m3r1-chat/chat.html delete mode 100644 cmd/m3r1-chat/main.go create mode 100644 main.go create mode 100644 static/overlay.html diff --git a/cmd/m3r1-chat/chat.html b/cmd/m3r1-chat/chat.html deleted file mode 100644 index a8c0e37..0000000 --- a/cmd/m3r1-chat/chat.html +++ /dev/null @@ -1,47 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> -<head> - <meta charset="UTF-8"> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <title>Minecraft Twitch Chat Overlay</title> - <style> - body { - background-color: transparent; - color: white; - font-family: 'Minecraft', sans-serif; - font-size: 16px; - margin: 0; - padding: 0; - overflow: hidden; - } - #chat { - position: absolute; - bottom: 0; - left: 0; - width: 100%; - height: 30%; - padding: 10px; - box-sizing: border-box; - background-color: rgba(0, 0, 0, 0.5); - overflow-y: auto; - } - .message { - margin-bottom: 5px; - } - </style> -</head> -<body> - <div id="chat"></div> - <script> - async function fetchChat() { - const response = await fetch('/chat'); - const data = await response.json(); - const chat = document.getElementById('chat'); - chat.innerHTML = data.messages.map(msg => `<div class="message">${msg}</div>`).join(''); - chat.scrollTop = chat.scrollHeight; - } - - setInterval(fetchChat, 1000); - </script> -</body> -</html> \ No newline at end of file diff --git a/cmd/m3r1-chat/main.go b/cmd/m3r1-chat/main.go deleted file mode 100644 index 3725a4e..0000000 --- a/cmd/m3r1-chat/main.go +++ /dev/null @@ -1,63 +0,0 @@ -package main - -import ( - "fmt" - "log" - "sync" - - _ "embed" - - "github.com/gempir/go-twitch-irc/v4" - "github.com/gin-gonic/gin" -) - -var ( - messages []string - mu sync.Mutex -) - -// go:embed chat.html -var defaultHTML []byte - -func main() { - // Set up Twitch client - client := twitch.NewClient("your_bot_username", "oauth:your_oauth_token") - - // Set up Gin web server - r := gin.Default() - - // Serve static files (HTML, CSS, JS) - r.Static("/static", "./static") - - // Endpoint to get chat messages - r.GET("/chat", func(c *gin.Context) { - mu.Lock() - defer mu.Unlock() - c.JSON(200, gin.H{ - "messages": messages, - }) - }) - - // Handle Twitch chat messages - client.OnPrivateMessage(func(message twitch.PrivateMessage) { - mu.Lock() - defer mu.Unlock() - messages = append(messages, fmt.Sprintf("%s: %s", message.User.Name, message.Message)) - if len(messages) > 100 { // Keep only the last 100 messages - messages = messages[1:] - } - }) - - // Connect to Twitch chat - client.Join("merithtk") - - go func() { - err := client.Connect() - if err != nil { - log.Fatalf("Error connecting to Twitch: %v", err) - } - }() - - // Start the web server - r.Run(":8080") -} diff --git a/main.go b/main.go new file mode 100644 index 0000000..997e2ca --- /dev/null +++ b/main.go @@ -0,0 +1,76 @@ +package main + +import ( + "fmt" + "log" + "sync" + + _ "embed" + + "github.com/gempir/go-twitch-irc/v4" + "github.com/gin-gonic/gin" +) + +var ( + // Store chat messages for each channel + channelMessages = make(map[string][]string) + mu sync.Mutex +) + +func main() { + // Set up Twitch client + client := twitch.NewAnonymousClient() // No need to log in as a bot + + // Set up Gin web server + r := gin.Default() + + // Serve static files (HTML, CSS, JS) + r.Static("/static", "./static") + + // Endpoint to get chat messages for a specific channel + r.GET("/chat/:channel", func(c *gin.Context) { + channel := c.Param("channel") + mu.Lock() + defer mu.Unlock() + messages, exists := channelMessages[channel] + if !exists { + c.JSON(200, gin.H{ + "messages": []string{}, + }) + return + } + c.JSON(200, gin.H{ + "messages": messages, + }) + }) + + // Handle Twitch chat messages + client.OnPrivateMessage(func(message twitch.PrivateMessage) { + mu.Lock() + defer mu.Unlock() + channel := message.Channel + messages := channelMessages[channel] + messages = append(messages, fmt.Sprintf("%s: %s", message.User.Name, message.Message)) + if len(messages) > 100 { // Keep only the last 100 messages + messages = messages[1:] + } + channelMessages[channel] = messages + }) + + // Automatically join channels when requested + r.GET("/chat/:channel/overlay", func(c *gin.Context) { + channel := c.Param("channel") + client.Join(channel) // Join the channel if not already joined + c.File("./static/overlay.html") // Serve the overlay HTML + }) + + // Start the web server + go func() { + err := client.Connect() + if err != nil { + log.Fatalf("Error connecting to Twitch: %v", err) + } + }() + + r.Run(":8080") +} diff --git a/static/overlay.html b/static/overlay.html new file mode 100644 index 0000000..e6a662b --- /dev/null +++ b/static/overlay.html @@ -0,0 +1,108 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Minecraft Twitch Chat Overlay</title> + <style> + /* Import Minecraft font */ + @import url('https://fonts.googleapis.com/css2?family=Minecraft&display=swap'); + + body { + background-color: transparent; + margin: 0; + padding: 0; + overflow: hidden; + } + + #chat { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 30%; + padding: 10px; + box-sizing: border-box; + overflow-y: auto; + display: flex; + flex-direction: column; + justify-content: flex-end; + background-color: transparent; + } + + .message { + font-family: 'Minecraft', sans-serif; + font-size: 16px; + color: white; + text-shadow: 2px 2px 0 #3f3f3f; + margin-bottom: 5px; + opacity: 0; + animation: fadeIn 0.5s ease-in-out forwards; + } + + @keyframes fadeIn { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); + } + } + + /* Fade out older messages */ + .message.fade-out { + animation: fadeOut 0.5s ease-in-out forwards; + } + + @keyframes fadeOut { + from { + opacity: 1; + transform: translateY(0); + } + to { + opacity: 0; + transform: translateY(-10px); + } + } + </style> +</head> +<body> + <div id="chat"></div> + <script> + // Extract the channel name from the URL + const channel = window.location.pathname.split('/')[2]; + + // Function to fetch chat messages + async function fetchChat() { + const response = await fetch(`/chat/${channel}`); + const data = await response.json(); + const chat = document.getElementById('chat'); + + // Clear existing messages + chat.innerHTML = ''; + + // Add new messages with fade-in animation + data.messages.forEach((msg, index) => { + const messageElement = document.createElement('div'); + messageElement.classList.add('message'); + messageElement.textContent = msg; + + // Fade out older messages if there are more than 10 + if (data.messages.length > 10 && index < data.messages.length - 10) { + messageElement.classList.add('fade-out'); + } + + chat.appendChild(messageElement); + }); + + // Scroll to the bottom + chat.scrollTop = chat.scrollHeight; + } + + // Fetch chat messages every second + setInterval(fetchChat, 1000); + </script> +</body> +</html> \ No newline at end of file