From 2bb2463aa5f1986fa2d3893c76d0d9a4b6a684ab Mon Sep 17 00:00:00 2001 From: Fdvkey Date: Wed, 15 Jul 2026 19:40:34 +0700 Subject: [PATCH] chore: remove documentation folder and temporary trace artifacts --- .../plans/2026-07-15-pure-go-exiv-plan.md | 412 ------------------ .../specs/2026-07-15-pure-go-exiv-design.md | 17 - 2 files changed, 429 deletions(-) delete mode 100644 docs/superpowers/plans/2026-07-15-pure-go-exiv-plan.md delete mode 100644 docs/superpowers/specs/2026-07-15-pure-go-exiv-design.md diff --git a/docs/superpowers/plans/2026-07-15-pure-go-exiv-plan.md b/docs/superpowers/plans/2026-07-15-pure-go-exiv-plan.md deleted file mode 100644 index 0a06480..0000000 --- a/docs/superpowers/plans/2026-07-15-pure-go-exiv-plan.md +++ /dev/null @@ -1,412 +0,0 @@ -# Pure-Go WebP EXIF RIFF Injector Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. - -**Goal:** Modify `helper/exif.go` and `helper/media_convert.go` to inject EXIF payloads directly into WebP RIFF byte slices entirely in Go memory, replacing `webpmux`. - -**Architecture:** We will implement an `InjectExif(webpBytes []byte, packName, publisher string) ([]byte, error)` function inside `helper/exif.go` to handle raw RIFF parsing in place, and strip out the old Temp File logic. Webpmux invocation in `helper/media_convert.go` will be removed. - -**Tech Stack:** Go (encoding/binary) - -## Global Constraints -- Target files: `helper/exif.go` and `helper/media_convert.go` -- Do not use CGO or any unstated 3rd party package for RIFF handling. Implement manually using `encoding/binary`. -- Format must be `VP8X` with the EXIF flag bit activated. - ---- - -### Task 1: Clean Up media_convert.go - -**Files:** -- Modify:`/Users/fd/Documents/perf/helper/media_convert.go` - -**Interfaces:** -- Consumes: Nothing -- Produces: `ConvertImageToWebp`, `ConvertVideoToWebp` - -- [ ] **Step 1: Simplify Convert methods** -Remove `InjectExif` from `media_convert.go` since it will be rewritten from scratch in `exif.go`. - -```go -package helper - -import ( - "bytes" - "fmt" - "os" - "os/exec" - "path/filepath" - - "github.com/google/uuid" -) - -func ConvertImageToWebp(imgData []byte) ([]byte, error) { - convertCmd := exec.Command("convert", "-", "-resize", "512x512", "-background", "none", "-compose", "Copy", "-gravity", "center", "-extent", "512x512", "-quality", "100", "png:-") - convertCmd.Stdin = bytes.NewReader(imgData) - var convertBuf bytes.Buffer - convertCmd.Stdout = &convertBuf - if err := convertCmd.Run(); err != nil { - return nil, fmt.Errorf("convert failed: %w", err) - } - - cwebpCmd := exec.Command("cwebp", "-quiet", "-mt", "-exact", "-q", "100", "-m", "6", "-alpha_q", "100", "-o", "-", "--", "-") - cwebpCmd.Stdin = &convertBuf - var cwebpBuf bytes.Buffer - cwebpCmd.Stdout = &cwebpBuf - if err := cwebpCmd.Run(); err != nil { - return nil, fmt.Errorf("cwebp failed: %w", err) - } - - return cwebpBuf.Bytes(), nil -} - -func ConvertVideoToWebp(vidData []byte) ([]byte, error) { - webpPath := filepath.Join("temp", fmt.Sprintf("%s.webp", uuid.New().String())) - defer os.Remove(webpPath) - - ffmpegCmd := exec.Command("ffmpeg", - "-y", "-hide_banner", "-loglevel", "error", - "-i", "pipe:0", "-f", "mp4", - "-ss", "00:00:00", "-t", "00:00:15", - "-vf", "fps=10,scale=720:-1:flags=lanczos:force_original_aspect_ratio=increase,crop=512:512,pad=512:512:(ow-iw)/2:(oh-ih)/2:color=#00000000,setsar=1", - "-compression_level", "6", - "-q:v", "60", "-loop", "0", - "-preset", "picture", "-an", "-fps_mode", "auto", - "-f", "webp", webpPath, - ) - ffmpegCmd.Stdin = bytes.NewReader(vidData) - if err := ffmpegCmd.Run(); err != nil { - return nil, fmt.Errorf("ffmpeg failed: %w", err) - } - - return os.ReadFile(webpPath) -} -``` - -- [ ] **Step 2: Check standard test suite** -Run: `go build ./...` - -- [ ] **Step 3: Commit** -```bash -git add helper/media_convert.go -git commit -m "refactor: remove InjectExif shell wrapper from media_convert" -``` - -### Task 2: Implement Pure-Go RIFF Injector - -**Files:** -- Modify:`/Users/fd/Documents/perf/helper/exif.go` - -**Interfaces:** -- Produces: `InjectExif(webpData []byte, packName, publisher string) ([]byte, error)` -- Consumes: Nothing - -- [ ] **Step 1: Write `helper/exif.go`** -Overwrite `/Users/fd/Documents/perf/helper/exif.go` with the completely new implementation. The previous dynamic `temp/default.exif` file logic is gone. - -```go -package helper - -import ( - "bytes" - "encoding/binary" - "encoding/json" - "fmt" - "math/big" -) - -type StickerMetadata struct { - PackId string `json:"sticker-pack-id"` - Name string `json:"sticker-pack-name"` - Publisher string `json:"sticker-pack-publisher"` - Emojis []string `json:"emojis,omitempty"` -} - -func writeUIntLE(buffer []byte, value, offset, byteLength int64) { - slice := make([]byte, byteLength) - val := new(big.Int) - val.SetUint64(uint64(value)) - valBytes := val.Bytes() - - tmp := make([]byte, len(valBytes)) - for i := range valBytes { - tmp[i] = valBytes[len(valBytes)-1-i] - } - copy(slice, tmp) - copy(buffer[offset:], slice) -} - -func createMetadataBytes(packName, publisher string) []byte { - exifObj := StickerMetadata{ - PackId: "com.wa.bot.sticker", - Name: packName, - Publisher: publisher, - Emojis: []string{"😀"}, - } - - exifJson, err := json.Marshal(exifObj) - if err != nil { - return nil - } - - bit := []byte{0x49, 0x49, 0x2A, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x41, 0x57, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00} - bit = append(bit, exifJson...) - writeUIntLE(bit, int64(len(exifJson)), 14, 4) - - return bit -} - -// InjectExif takes raw WebP bytes and constructs a new WebP RIFF byte slice containing the EXIF metadata -func InjectExif(webpData []byte, packName, publisher string) ([]byte, error) { - if len(webpData) < 12 || string(webpData[0:4]) != "RIFF" || string(webpData[8:12]) != "WEBP" { - return nil, fmt.Errorf("not a valid WEBP file") - } - - var width, height uint32 - hasVP8X := false - var vp8xFlags byte - var vp8xBytes []byte - - var chunks [][]byte - - // Default defaults for VP8X canvas sizes - width = 512 - height = 512 - - offset := 12 - for offset < len(webpData) { - if offset+8 > len(webpData) { - break - } - chunkID := string(webpData[offset : offset+4]) - chunkSize := binary.LittleEndian.Uint32(webpData[offset+4 : offset+8]) - - paddedSize := chunkSize - if paddedSize%2 != 0 { - paddedSize++ - } - - if offset+8+int(paddedSize) > len(webpData) { - break - } - - chunkData := webpData[offset+8 : offset+8+int(paddedSize)] - - switch chunkID { - case "VP8X": - hasVP8X = true - vp8xFlags = chunkData[0] - vp8xBytes = chunkData - // extract dimensions - wBytes := []byte{chunkData[4], chunkData[5], chunkData[6], 0} - hBytes := []byte{chunkData[7], chunkData[8], chunkData[9], 0} - width = binary.LittleEndian.Uint32(wBytes) + 1 - height = binary.LittleEndian.Uint32(hBytes) + 1 - case "VP8 ": - if !hasVP8X { - // extract 14 bit scale block - w := uint32(chunkData[6]) | (uint32(chunkData[7]) << 8) - width = w & 0x3FFF - h := uint32(chunkData[8]) | (uint32(chunkData[9]) << 8) - height = h & 0x3FFF - } - chunks = append(chunks, webpData[offset:offset+8+int(paddedSize)]) - case "VP8L": - if !hasVP8X { - // Parse bits 1-28 for w/h - b0 := uint32(chunkData[1]) - b1 := uint32(chunkData[2]) - b2 := uint32(chunkData[3]) - b3 := uint32(chunkData[4]) - width = 1 + (((b1 & 0x3F) << 8) | b0) - height = 1 + (((b3 & 0xF) << 10) | (b2 << 2) | ((b1 & 0xC0) >> 6)) - } - chunks = append(chunks, webpData[offset:offset+8+int(paddedSize)]) - default: - if chunkID != "EXIF" { - chunks = append(chunks, webpData[offset:offset+8+int(paddedSize)]) - } - } - offset += 8 + int(paddedSize) - } - - exifMeta := createMetadataBytes(packName, publisher) - if exifMeta == nil { - return nil, fmt.Errorf("failed to create exif byte payload") - } - - // Turn on EXIF flag (bit 3) in VP8X - if !hasVP8X { - vp8xBytes = make([]byte, 10) - vp8xFlags = 0x08 // EXIF flag is bit 3 - vp8xBytes[0] = vp8xFlags - w := width - 1 - h := height - 1 - vp8xBytes[4] = byte(w) - vp8xBytes[5] = byte(w >> 8) - vp8xBytes[6] = byte(w >> 16) - vp8xBytes[7] = byte(h) - vp8xBytes[8] = byte(h >> 8) - vp8xBytes[9] = byte(h >> 16) - } else { - vp8xBytes[0] = vp8xFlags | 0x08 - } - - var buf bytes.Buffer - buf.WriteString("RIFF") - buf.Write([]byte{0, 0, 0, 0}) // Total size placeholder - buf.WriteString("WEBP") - - // Write VP8X - buf.WriteString("VP8X") - vp8xSize := make([]byte, 4) - binary.LittleEndian.PutUint32(vp8xSize, 10) - buf.Write(vp8xSize) - buf.Write(vp8xBytes) - - // Write existing chunks - for _, chunk := range chunks { - buf.Write(chunk) - } - - // Write EXIF - buf.WriteString("EXIF") - exifSize := uint32(len(exifMeta)) - exifSizeSlice := make([]byte, 4) - binary.LittleEndian.PutUint32(exifSizeSlice, exifSize) - buf.Write(exifSizeSlice) - buf.Write(exifMeta) - if exifSize%2 != 0 { - buf.WriteByte(0) - } - - result := buf.Bytes() - totalSize := uint32(len(result) - 8) - binary.LittleEndian.PutUint32(result[4:8], totalSize) - - return result, nil -} -``` - -- [ ] **Step 2: Check test suite** -Run: `go build ./...` - -- [ ] **Step 3: Commit** -```bash -git add helper/exif.go -git commit -m "feat: implement pure-go RIFF EXIF injector" -``` - -### Task 3: Update cmds/media/sticker.go Signature - -**Files:** -- Modify:`/Users/fd/Documents/perf/cmds/media/sticker.go` - -**Interfaces:** -- Consumes: `helper.InjectExif(rawWebp, packName, publisher)` - -- [ ] **Step 1: Replace ResolveExif usages in `cmds/media/sticker.go`** -Read `ctx.Arguments()` directly to compute `packName` and `publisher` locally instead of calling `helper.ResolveExif`. Use the same ENV logic as fallback defaults if args are empty. Remove `helper.ResolveExif` code context cleanup. - -```go -package media - -import ( - "context" - "fmt" - "os" - "strings" - - hc "neo/context" - "neo/core" - "neo/helper" -) - -func init() { core.Default.Register(Sticker) } - -var Sticker = &core.Command{ - Name: "sticker", - Aliases: []string{"s", "stiker"}, - Category: "media", - Description: "Create sticker from image/video or rewrite existing sticker EXIF", - Run: func(ctx *hc.Ctx) { - ctx.React("👌") - - args := ctx.Arguments() - packName := os.Getenv("STICKER_NAME") - if packName == "" { - packName = "Bot" - } - publisher := os.Getenv("STICKER_PUBLISHER") - if publisher == "" { - publisher = "Bot" - } - - if len(args) > 0 { - argStr := strings.Join(args, " ") - parts := strings.Split(argStr, "|") - packName = strings.TrimSpace(parts[0]) - publisher = "Bot" - if len(parts) > 1 { - publisher = strings.TrimSpace(parts[1]) - } - } - - msg := ctx.Message() - quoted := hc.GetQuotedMessage(msg) - - var err error - var rawWebp []byte - var mediaData []byte - - if img := msg.GetImageMessage(); img != nil { - mediaData, err = ctx.Client().Download(context.Background(), img) - if err == nil { - rawWebp, err = helper.ConvertImageToWebp(mediaData) - } - } else if img := quoted.GetImageMessage(); img != nil && quoted != nil { - mediaData, err = ctx.Client().Download(context.Background(), img) - if err == nil { - rawWebp, err = helper.ConvertImageToWebp(mediaData) - } - } else if vid := msg.GetVideoMessage(); vid != nil { - mediaData, err = ctx.Client().Download(context.Background(), vid) - if err == nil { - rawWebp, err = helper.ConvertVideoToWebp(mediaData) - } - } else if vid := quoted.GetVideoMessage(); vid != nil && quoted != nil { - mediaData, err = ctx.Client().Download(context.Background(), vid) - if err == nil { - rawWebp, err = helper.ConvertVideoToWebp(mediaData) - } - } else if smsg := quoted.GetStickerMessage(); smsg != nil && quoted != nil { - rawWebp, err = ctx.Client().Download(context.Background(), smsg) - } else { - ctx.Reply("error: reply to image/video/sticker or send with caption") - return - } - - if err != nil { - ctx.Reply(fmt.Sprintf("error processing media: %v", err)) - return - } - - finalSticker, err := helper.InjectExif(rawWebp, packName, publisher) - if err != nil { - ctx.Reply(fmt.Sprintf("error injecting EXIF: %v", err)) - return - } - - ctx.SendSticker(finalSticker) - }, -} -``` - -- [ ] **Step 2: Verify Compilation** -Run: `go build ./...` - -- [ ] **Step 3: Commit** -```bash -git add cmds/media/sticker.go -git commit -m "feat: use pure-go exif injector in sticker command" -``` diff --git a/docs/superpowers/specs/2026-07-15-pure-go-exiv-design.md b/docs/superpowers/specs/2026-07-15-pure-go-exiv-design.md deleted file mode 100644 index 8c2de3d..0000000 --- a/docs/superpowers/specs/2026-07-15-pure-go-exiv-design.md +++ /dev/null @@ -1,17 +0,0 @@ -# Pure-Go WebP EXIF RIFF Injector - -## 1. Goal -Completely remove file-based IO and the `webpmux` dependency by weaving the EXIF chunk into the WebP RIFF byte struct physically in memory. - -## 2. Architecture -Instead of using `webpmux` passing paths around, `helper/exif.go` will implement `InjectExif(webpBytes []byte, packName, publisher string) ([]byte, error)`. - -## 3. RIFF Parsing Logic -1. Validate `RIFF` and `WEBP` signatures. -2. Read all chunks to extract Canvas Width/Height (from `VP8X`, `VP8L`, or `VP8 `). -3. Identify if `VP8X` is missing, and if so, construct it. We must ensure the `EXIF` bit flag is set. -4. Construct the custom `EXIF` chunk (which holds the exact binary array and JSON metadata we validated via F-BOT_GO earlier). -5. Append `EXIF` to the end of the WebP chunks, update the main `RIFF` file size pointer, and return the aggregated `[]byte` slice. - -## 4. Main Command Refactor -`cmds/media/sticker.go` will stop requesting files via `ResolveExif()`. It will simply pass the raw Webp bytes received from `ConvertImageToWebp` or `ConvertVideoToWebp` into `InjectExif` and instantly upload the resulting byte array.