wow that took awhile

This commit is contained in:
cottongin
2025-11-01 10:40:53 -04:00
parent 9143a0bc60
commit bd9513b86c
44 changed files with 4484 additions and 76 deletions

View File

@@ -0,0 +1,99 @@
package bkosmi
import (
"bytes"
"encoding/json"
"fmt"
"io"
"mime/multipart"
"net/http"
"github.com/sirupsen/logrus"
)
const (
kosmiImageUploadURL = "https://img.kosmi.io/"
)
// ImageUploadResponse represents the response from Kosmi image upload endpoint
type ImageUploadResponse struct {
Filename string `json:"filename"`
}
// UploadImage uploads an image to Kosmi's CDN and returns the URL
func UploadImage(imageData []byte, filename string) (string, error) {
logrus.WithFields(logrus.Fields{
"filename": filename,
"size": len(imageData),
}).Debug("Uploading image to Kosmi CDN")
// Create multipart form body
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
// Add file field
part, err := writer.CreateFormFile("file", filename)
if err != nil {
return "", fmt.Errorf("failed to create form file: %w", err)
}
if _, err := part.Write(imageData); err != nil {
return "", fmt.Errorf("failed to write image data: %w", err)
}
// Close the multipart writer to finalize the body
if err := writer.Close(); err != nil {
return "", fmt.Errorf("failed to close multipart writer: %w", err)
}
// Create HTTP request
req, err := http.NewRequest("POST", kosmiImageUploadURL, body)
if err != nil {
return "", fmt.Errorf("failed to create request: %w", err)
}
// Set required headers
req.Header.Set("Content-Type", writer.FormDataContentType())
req.Header.Set("Origin", "https://app.kosmi.io")
req.Header.Set("Referer", "https://app.kosmi.io/")
req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36")
// Send request
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return "", fmt.Errorf("failed to send request: %w", err)
}
defer resp.Body.Close()
// Check status code
if resp.StatusCode != http.StatusOK {
bodyBytes, _ := io.ReadAll(resp.Body)
return "", fmt.Errorf("upload failed with status %d: %s", resp.StatusCode, string(bodyBytes))
}
// Read response body for debugging
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("failed to read response body: %w", err)
}
logrus.WithField("response", string(bodyBytes)).Debug("Upload response body")
// Parse response
var result ImageUploadResponse
if err := json.Unmarshal(bodyBytes, &result); err != nil {
return "", fmt.Errorf("failed to parse response: %w (body: %s)", err, string(bodyBytes))
}
if result.Filename == "" {
return "", fmt.Errorf("no filename in response (body: %s)", string(bodyBytes))
}
// Construct the full URL from the filename
imageURL := fmt.Sprintf("https://img.kosmi.io/%s", result.Filename)
logrus.WithField("url", imageURL).Info("Successfully uploaded image to Kosmi CDN")
return imageURL, nil
}

View File

@@ -8,6 +8,7 @@ import (
"github.com/42wim/matterbridge/bridge"
"github.com/42wim/matterbridge/bridge/config"
"github.com/42wim/matterbridge/bridge/jackbox"
)
const (
@@ -26,11 +27,12 @@ type KosmiClient interface {
// Bkosmi represents the Kosmi bridge
type Bkosmi struct {
*bridge.Config
client KosmiClient
roomID string
roomURL string
connected bool
msgChannel chan config.Message
client KosmiClient
roomID string
roomURL string
connected bool
msgChannel chan config.Message
jackboxClient *jackbox.Client
}
// New creates a new Kosmi bridge instance
@@ -154,6 +156,21 @@ func (b *Bkosmi) handleIncomingMessage(payload *NewMessagePayload) {
return
}
// Check for votes (thisgame++ or thisgame--)
// Only process votes from non-relayed messages
if !jackbox.IsRelayedMessage(body) {
if isVote, voteType := jackbox.DetectVote(body); isVote {
b.Log.Debugf("Detected vote from %s: %s", username, voteType)
if b.jackboxClient != nil {
go func() {
if err := b.jackboxClient.SendVote(username, voteType, timestamp); err != nil {
b.Log.Errorf("Failed to send vote to Jackbox API: %v", err)
}
}()
}
}
}
// Create Matterbridge message
// Use "main" as the channel name for gateway matching
// Don't add prefix here - let the gateway's RemoteNickFormat handle it
@@ -169,12 +186,12 @@ func (b *Bkosmi) handleIncomingMessage(payload *NewMessagePayload) {
// Send to Matterbridge
b.Log.Debugf("Forwarding to Matterbridge channel=%s account=%s: %s", rmsg.Channel, rmsg.Account, rmsg.Text)
if b.Remote == nil {
b.Log.Error("Remote channel is nil! Cannot forward message")
return
}
b.Remote <- rmsg
}
@@ -219,3 +236,8 @@ func extractRoomID(url string) (string, error) {
return "", fmt.Errorf("could not extract room ID from URL: %s", url)
}
// SetJackboxClient sets the Jackbox API client for this bridge
func (b *Bkosmi) SetJackboxClient(client *jackbox.Client) {
b.jackboxClient = client
b.Log.Info("Jackbox client injected into Kosmi bridge")
}