everytab/pipeline/05_bundle_gen/bundle.go

84 lines
2.1 KiB
Go

package main
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
)
// BundleEntry is one tab in a bundle JSON file.
type BundleEntry struct {
URL string `json:"url"`
Title string `json:"title"`
Icon string `json:"icon"`
IconW int `json:"icon_w,omitempty"`
IconH int `json:"icon_h,omitempty"`
IframeOk bool `json:"iframe_ok"`
}
// Bundle is the top-level JSON structure.
type Bundle struct {
Entries []BundleEntry `json:"entries"`
}
// buildEntry creates a BundleEntry for a host, converting its icon if available.
func buildEntry(host HostRow, iconsDir string, logWriter *LogWriter, stats *Stats) BundleEntry {
entry := BundleEntry{
URL: host.Protocol + "://" + host.Hostname,
Title: host.HtmlTitle,
Icon: "",
IframeOk: host.IframeAllowed,
}
if host.BestIconHash == "" {
return entry
}
encoded, w, h, convertErr := safeConvert(host.BestIconHash, iconsDir)
if convertErr != "" {
stats.ConvertErrors.Add(1)
logLine := fmt.Sprintf("CONVERT_ERROR: %s %s", host.Hostname, convertErr)
fmt.Println(logLine)
if logWriter != nil {
logWriter.Write(logLine, true)
}
return entry
}
entry.Icon = encoded
entry.IconW = w
entry.IconH = h
return entry
}
// safeConvert wraps convertIconToBase64PNG with panic recovery.
func safeConvert(hash, iconsDir string) (encoded string, w, h int, errMsg string) {
defer func() {
if r := recover(); r != nil {
errMsg = fmt.Sprintf("panic: %v", r)
}
}()
var err error
encoded, w, h, err = convertIconToBase64PNG(hash, iconsDir)
if err != nil {
return "", 0, 0, err.Error()
}
return encoded, w, h, ""
}
func serializeBundle(entries []BundleEntry) ([]byte, error) {
bundle := Bundle{Entries: entries}
return json.Marshal(bundle)
}
func writeBundleLocal(outputDir string, index int, data []byte) error {
path := filepath.Join(outputDir, fmt.Sprintf("%06d.json", index))
return os.WriteFile(path, data, 0644)
}
func writeBundleS3(bucket string, index int, data []byte) error {
key := fmt.Sprintf("tabs/%06d.json", index)
return s3UploadBundle(bucket, key, data)
}