Files
tiennm99 277c913f71 refactor(random)!: configure the renderer by base URL as RENDERER_URL
The bot now takes the renderer's base URL and appends each /api/<name>
route itself, instead of taking the full /api/gif endpoint and swapping
its last path segment for /gacha and /genshin. The client, its files, and
its errors are named after the renderer rather than wheelofnames; the
/wheelofnames command keeps its name.

BREAKING CHANGE: WHEELOFNAMES_API_URL is replaced by RENDERER_URL, which
holds the base URL (e.g. http://renderer:3000) rather than the /api/gif
endpoint. compose.yml sets it, so Coolify needs no value.
2026-10-03 11:52:50 +07:00

82 lines
2.2 KiB
Go

package random
import (
"bytes"
"context"
"encoding/json"
"fmt"
"strings"
)
const (
gachaRemoteFPS = 24
gachaRemoteWidth = 640
gachaRemoteHeight = 360
)
// gachaStyle is one wish animation the renderer serves: its route name under
// /api, the clip length in seconds, and the frame size it renders for a
// gachaRemoteWidth request.
type gachaStyle struct {
Path string
Duration int
Width int
Height int
}
var (
// The card-pack wish is portrait: the requested width is its long edge.
gachaStyleCardPack = gachaStyle{Path: "gacha", Duration: 6, Width: gachaRemoteHeight, Height: gachaRemoteWidth}
gachaStyleGenshin = gachaStyle{Path: "genshin", Duration: 7, Width: gachaRemoteWidth, Height: gachaRemoteHeight}
)
type gachaRenderRequest struct {
Label string `json:"label"`
Rarity int `json:"rarity"`
FPS int `json:"fps"`
Width int `json:"width"`
}
// RenderGacha returns the MP4 wish animation named path revealing label at
// rarity stars.
func (c rendererClient) RenderGacha(ctx context.Context, path, label string, rarity int) ([]byte, error) {
endpoint, err := c.endpoint(path)
if err != nil {
return nil, err
}
if strings.TrimSpace(label) == "" {
return nil, fmt.Errorf("renderer gacha label empty")
}
if rarity < gachaMinRarity || rarity > gachaMaxRarity {
return nil, fmt.Errorf("renderer gacha rarity %d out of range", rarity)
}
body, err := json.Marshal(gachaRenderRequest{
Label: label,
Rarity: rarity,
FPS: gachaRemoteFPS,
Width: gachaRemoteWidth,
})
if err != nil {
return nil, fmt.Errorf("renderer gacha request encode failed: %w", err)
}
return c.post(ctx, endpoint, body, "video/mp4", isMP4)
}
// isMP4 checks for the ISO base media "ftyp" box that opens every MP4.
func isMP4(data []byte) bool {
return len(data) >= 8 && bytes.Equal(data[4:8], []byte("ftyp"))
}
func renderGachaAnimation(ctx context.Context, style gachaStyle, label string, rarity int) (renderedAnimation, error) {
data, err := newRendererClientFromEnv().RenderGacha(ctx, style.Path, label, rarity)
if err != nil {
return renderedAnimation{}, err
}
return renderedAnimation{
Data: data,
Duration: style.Duration,
Width: style.Width,
Height: style.Height,
}, nil
}