Something went wrong. Try again.
holy moly. a cat that says holy moly (or anything else you want it to). original image by __[x.com/BasiilLeaf](https://x.com/BasiilLeaf/status/1704587547853406445?lang=en)__ holymoly.cat
Something went wrong. Try again.
holymoly.cat main.go
12 kB · 409 lines
Go
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410/*Filename: main.goDescription: holy moly. a cat that says holy moly (or anything else you want it to). original image by x.com/BasiilLeafCreated by: osh at: 20:19 on Monday, the 20th of July, 2026Last edited 00:27 on Friday, the 21st of August, 2026*/
package main
import ( "bytes" "context" "crypto/sha256" _ "embed" "fmt" "html" "image" "image/color" "image/draw" "image/png" "io" "log" "net/http" "os" "os/exec" "path/filepath" "regexp" "strings"
xdraw "golang.org/x/image/draw" "golang.org/x/image/font" "golang.org/x/image/font/gofont/goregular" "golang.org/x/image/font/opentype" "golang.org/x/image/math/fixed"
"github.com/lrstanley/go-ytdlp")
//go:embed holymolyblank.pngvar holymolyblank []byte
//go:embed holymolycutout.pngvar holymolycutout []byte
const ( textX = 458 // x coord speech bubble centre textY = 152 // y coord speech bubble centre maxTextWidth = 160 // max width before overflow of the text bubble maxLines = 3 // max number of lines total maxFontSize = 10 // max font size that the text can be minFontSize = 8 // min font size that the text can be
cutoutX = 363 // speech bubble cutout left cutoutY = 106 // speech bubble cutout top cutoutW = 188 // speech bubble cutout width cutoutH = 94 // speech bubble cutout height
textRescaleQuality = 2 // text is rendered at 1/textRescaleQuality and then rescaled back up)
var ( baseImage image.Image cutoutImage image.Image gofont *opentype.Font
cacheDir = filepath.Join(os.TempDir(), "holymoly-cache") cutoutPath = filepath.Join(os.TempDir(), "holymoly-cutout.png") cookiesPath string)
func main() { // holymoly.png var err error baseImage, err = png.Decode(bytes.NewReader(holymolyblank)) if err != nil { log.Fatal(err) } cutoutImage, err = png.Decode((bytes.NewReader(holymolycutout))) if err != nil { log.Fatal(err) } gofont, err = opentype.Parse(goregular.TTF) if err != nil { log.Fatal(err) } if err := os.WriteFile(cutoutPath, holymolycutout, 0o644); err != nil { log.Fatal(err) }
// setup ytdlp if cookies := os.Getenv("COOKIES"); cookies != "" { b, err := os.ReadFile(cookies) if err != nil { log.Fatal("cookies:", err) } cookiesPath = filepath.Join(os.TempDir(), "cookies.txt") if err := os.WriteFile(cookiesPath, b, 0o600); err != nil { log.Fatal(err) } } if os.Getenv("FFMPEG") == "" { log.Fatalln("$FFMPEG unset") }
installed, err := ytdlp.InstallAll(context.Background()) for _, elem := range installed { if elem.Downloaded { log.Println("downloaded", elem.Executable, "version", elem.Version) } } if _, err := ytdlp.New().UpdateTo(context.Background(), "nightly"); err != nil { log.Println("yt-dlp update:", err) }
// start the server var port string if port = os.Getenv("PORT"); port == "" { log.Fatalln("$PORT unset") } port = ":" + port log.Println("started on", port) http.HandleFunc("/", handle) log.Fatal(http.ListenAndServe(port, nil))}
// parse what we pass with ?text + any flagsfunc handle(w http.ResponseWriter, r *http.Request) { text := r.URL.Query().Get("text")
if r.URL.Path != "/" { http.NotFound(w, r) return }
// embed credit when viewed in a browser const pageHTML = ` <!doctype html><title>holy moly</title> <body style="margin:0;height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:1rem; color:black;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif; "> <a href="%s" target="_blank"><img src="%s" style="max-width:80vw"></a> <a href="%s" target="_blank" style="color:black;" >cat by @BasiilLeaf ↗ </a> <p style="text-align:center;line-height:2rem"> <br> change what's said by adding ?text= to the url, <a href="?text=:3" style="color:black">like this</a>. <br> _ for a space, \ for a new line, <a href="?text=holy\moly_!" style="color:black">like this</a>. <br> embeds into anywhere as an image. <br> <a href="https://tangled.org/did:plc:ff263yce4lswuvvw7jefj6eo" target="_blank" style="color:black;">source code: Tangled.sh ↗ </a> </p> `
if r.Header.Get("Sec-Fetch-Dest") == "document" { w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Header().Set("Vary", "Sec-Fetch-Dest") fmt.Fprintf(w, pageHTML, "https://x.com/BasiilLeaf/status/1704587547853406445", html.EscapeString(r.URL.RequestURI()), "https://x.com/BasiilLeaf/status/1704587547853406445") return }
// embed media — take the raw tail after embed= so a pasted url keeps its own ?&… if _, media, ok := strings.Cut(r.URL.RawQuery, "embed="); ok && media != "" { gif, err := embed(r.Context(), media) if err != nil { http.Error(w, "render failed", http.StatusInternalServerError) log.Printf("embed %q: %v", media, err) return }
w.Header().Set("Content-Type", "image/gif") w.Header().Set("Cache-Control", "public, max-age=86400") w.Header().Set("Vary", "Sec-Fetch-Dest") w.Write(gif) return }
// parse text = strings.ReplaceAll(text, "_", " ") chamame := r.URL.Query().Get("chamame") == "oshdubh" credit := r.URL.Query().Get("credit") != "none" && !chamame if chamame { re := regexp.MustCompile(`\s*\(.*\)`) text = re.ReplaceAllString(text, "") }
if strings.TrimSpace(text) == "" { text = "holy moly" }
// return the image face, lines, err := fit(text) var img []byte if err == nil { img, err = render(face, lines, credit) } if err != nil { http.Error(w, "render failed", http.StatusInternalServerError) log.Printf("render %q: %v", lines, err) return }
w.Header().Set("Content-Type", "image/png") w.Header().Set("Cache-Control", "public, max-age=86400") w.Header().Set("Vary", "Sec-Fetch-Dest") w.Write(img)
var logstr strings.Builder for query, values := range r.URL.Query() { fmt.Fprintf(&logstr, "%v: %v ", query, strings.Join(values, ", ")) } log.Println(logstr.String())}
// composite the imagefunc render(face font.Face, lines []string, credit bool) ([]byte, error) {
// build our canvas out := image.NewRGBA(baseImage.Bounds()) draw.Draw(out, out.Bounds(), image.White, image.Point{}, draw.Src) draw.Draw(out, out.Bounds(), baseImage, image.Point{}, draw.Over)
small := image.NewRGBA(image.Rect(0, 0, out.Bounds().Dx()/textRescaleQuality, out.Bounds().Dy()/textRescaleQuality)) // smaller canvas for lower quality text metrics := face.Metrics()
// where we want to draw onto lineHeight := metrics.Height blockTop := fixed.I(textY/textRescaleQuality) - lineHeight.Mul(fixed.I(len(lines)))/2
// draw the lines for i, line := range lines { width := font.MeasureString(face, line) d := font.Drawer{ Dst: small, Src: image.Black, Face: face, Dot: fixed.Point26_6{ // draw in the centre, using i to make it centred vertically for multiline strings X: fixed.I(textX/textRescaleQuality) - width/2, Y: blockTop + lineHeight.Mul(fixed.I(i)) + metrics.Ascent, }, } d.DrawString(line) }
// baked in credit if credit { cf, err := opentype.NewFace(gofont, &opentype.FaceOptions{ Size: 7, DPI: 90, Hinting: font.HintingFull, }) if err != nil { return nil, err } d := font.Drawer{ Dst: small, Src: image.NewUniform(color.Gray{Y: 128}), Face: cf, Dot: fixed.Point26_6{X: fixed.I(4), Y: cf.Metrics().Ascent + fixed.I(3)}, } d.DrawString("@BasiilLeaf") }
xdraw.NearestNeighbor.Scale(out, out.Bounds(), small, small.Bounds(), xdraw.Over, nil)
// encode the bytes as a png and return var buf bytes.Buffer if err := png.Encode(&buf, out); err != nil { return nil, err } return buf.Bytes(), nil}
// resize the text, respecting our limits, to get the text into the speech bubblefunc fit(text string) (face font.Face, lines []string, err error) { limit := fixed.I(maxTextWidth / textRescaleQuality) // measure based on our lower qualty text canvas
// scale down until it fits for size := maxFontSize; size >= minFontSize; size-- { face, err = opentype.NewFace(gofont, &opentype.FaceOptions{ Size: float64(size), DPI: 72, Hinting: font.HintingFull, }) if err != nil { return nil, nil, err }
lines = lines[:0] for seg := range strings.SplitSeq(text, "\\") { line := "" for word := range strings.FieldsSeq(seg) { switch { case line == "": // first word line = word case font.MeasureString(face, line+" "+word) > limit: // would overflow lines = append(lines, line) line = word default: line += " " + word } } lines = append(lines, line) // force the break at backslashes }
// catch any words too big for the bubble, giving them their own lines widest := fixed.Int26_6(0) for _, l := range lines { if w := font.MeasureString(face, l); w > widest { widest = w } }
if len(lines) <= maxLines && widest <= limit { return face, lines, nil } } return face, lines, nil}
// download the passed media, and composite an image with it embeddedfunc embed(ctx context.Context, url string) ([]byte, error) { key := fmt.Sprintf("%x", sha256.Sum256([]byte(url)))
// serve a previously rendered gif if we have one cached := filepath.Join(cacheDir, key+".gif") if cachedBytes, err := os.ReadFile(cached); err == nil { log.Println("serving cached gif for", url) return cachedBytes, nil }
log.Println("downloading", url) ext := strings.ToLower(filepath.Ext(strings.SplitN(url, "?", 2)[0])) // filetype detect switch ext { case ".png", ".jpg", ".jpeg", ".gif", ".webp", ".bmp": dst := filepath.Join(os.TempDir(), key+ext) req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return nil, err } resp, err := http.DefaultClient.Do(req) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("fetch %s: %s", url, resp.Status) } f, err := os.Create(dst) if err != nil { return nil, err } if _, err := io.Copy(f, resp.Body); err != nil { f.Close() return nil, err } f.Close()
default: out := filepath.Join(os.TempDir(), key+".%(ext)s") //lowest quality version download := ytdlp.New(). Format("wv*[height<=480]+wa/w[height<=480]"). Output(out) if cookiesPath != "" { download = download.Cookies(cookiesPath) } details, _ := download.Run(ctx, url) if details.ExitCode != 0 { return nil, fmt.Errorf("exited with code %v: %v\n", details.ExitCode, details.Stderr) } log.Println("running", details.Executable, strings.Join(details.Args, " ")) }
matches, err := filepath.Glob(filepath.Join(os.TempDir(), key+".*")) if err != nil || len(matches) == 0 { return nil, fmt.Errorf("no download saved") } video := matches[0] defer os.Remove(video)
// ffmpeg reformatting filter := fmt.Sprintf( "color=c=white:s=645x432:d=600[bg];"+ "[0:v]scale=%d:%d:force_original_aspect_ratio=increase,crop=%d:%d,fps=15[v];"+ "[bg][v]overlay=%d:%d:shortest=1[bgv];"+ "[bgv][1:v]overlay=0:0[flat];"+ "[flat]split[a][b];[a]palettegen[p];[b][p]paletteuse", cutoutW, cutoutH, cutoutW, cutoutH, cutoutX, cutoutY, )
// gif it var buf bytes.Buffer cmd := exec.CommandContext(ctx, os.Getenv("FFMPEG"), "-i", video, "-i", cutoutPath, "-filter_complex", filter, "-f", "gif", "pipe:1", ) cmd.Stdout = &buf if err := cmd.Run(); err != nil { return nil, err }
// cache the result if err := os.MkdirAll(cacheDir, 0o755); err == nil { os.WriteFile(cached, buf.Bytes(), 0o644) } return buf.Bytes(), nil}