diff options
| author | Xe Iaso <me@xeiaso.net> | 2024-05-16 13:42:18 -0400 |
|---|---|---|
| committer | Xe Iaso <me@xeiaso.net> | 2024-05-16 13:42:18 -0400 |
| commit | 78fac2cb8f559fe549c25553666c6219283ad003 (patch) | |
| tree | 8a0a7ce3ac931890d3d9dac5db6464b80b31768d /cmd/mimi/modules | |
| parent | 0074ae35503b84bc04062e3dba2d9facc59e13c9 (diff) | |
| download | x-78fac2cb8f559fe549c25553666c6219283ad003.tar.xz x-78fac2cb8f559fe549c25553666c6219283ad003.zip | |
cmd/mimi: convert HEIC images to JPEG automatically
Signed-off-by: Xe Iaso <me@xeiaso.net>
Diffstat (limited to 'cmd/mimi/modules')
| -rw-r--r-- | cmd/mimi/modules/discord/heic2jpeg/heic2jpeg.go | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/cmd/mimi/modules/discord/heic2jpeg/heic2jpeg.go b/cmd/mimi/modules/discord/heic2jpeg/heic2jpeg.go new file mode 100644 index 0000000..f0282e5 --- /dev/null +++ b/cmd/mimi/modules/discord/heic2jpeg/heic2jpeg.go @@ -0,0 +1,138 @@ +package heic2jpeg + +import ( + "context" + "io" + "log/slog" + "net/http" + "os" + "os/exec" + "path/filepath" + "strings" + "time" + + "github.com/bwmarrin/discordgo" + "within.website/x/cmd/mimi/internal" +) + +func p[T any](v T) *T { + return &v +} + +type Module struct{} + +func (m *Module) Register(s *discordgo.Session) { + s.AddHandler(m.heic2jpeg) +} + +func New() *Module { + return &Module{} +} + +func (m *Module) heic2jpeg(s *discordgo.Session, mc *discordgo.MessageCreate) { + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + if len(mc.Attachments) == 0 { + return + } + + atts := []*discordgo.MessageAttachment{} + + for _, att := range mc.Attachments { + switch att.ContentType { + case "image/heic", "image/avif": + atts = append(atts, att) + } + } + + if len(atts) == 0 { + return + } + + os.MkdirAll(filepath.Join(internal.DataDir(), "heic2jpeg"), 0755) + dir, err := os.MkdirTemp(filepath.Join(internal.DataDir(), "heic2jpeg"), "heic2jpeg") + if err != nil { + s.ChannelMessageSend(mc.ChannelID, "failed to create temp dir") + slog.Error("failed to create temp dir", "err", err) + return + } + defer os.RemoveAll(dir) + + files := make([]*discordgo.File, 0, len(mc.Attachments)) + + for _, att := range mc.Attachments { + // download the image + req, err := http.NewRequestWithContext(ctx, "GET", att.URL, nil) + if err != nil { + s.ChannelMessageSend(mc.ChannelID, "failed to download image") + slog.Error("failed to download image", "err", err) + return + } + + slog.Info("converting", "url", req.URL.String()) + + resp, err := http.DefaultClient.Do(req) + if err != nil { + s.ChannelMessageSend(mc.ChannelID, "failed to download image") + slog.Error("failed to download image", "err", err) + return + } + defer resp.Body.Close() + + fname := filepath.Join(dir, filepath.Base(req.URL.Path)) + fnameStem := strings.TrimSuffix(fname, filepath.Ext(fname)) + fnameJPEG := fnameStem + ".jpeg" + + fout, err := os.Create(fname) + if err != nil { + s.ChannelMessageSend(mc.ChannelID, "failed to save image") + slog.Error("failed to save image", "err", err) + return + } + defer fout.Close() + + if _, err := io.Copy(fout, resp.Body); err != nil { + s.ChannelMessageSend(mc.ChannelID, "failed to save image") + slog.Error("failed to save image", "err", err) + return + } + + // convert the image + cmd := exec.CommandContext(ctx, "magick", fname, "-quality", "80%", fnameJPEG) + if err := cmd.Run(); err != nil { + s.ChannelMessageSend(mc.ChannelID, "failed to convert image") + slog.Error("failed to convert image", "err", err) + return + } + + fin, err := os.Open(fnameJPEG) + if err != nil { + s.ChannelMessageSend(mc.ChannelID, "failed to open converted image") + slog.Error("failed to open converted image", "err", err) + return + } + defer fin.Close() + + // queue the image for sending + files = append(files, &discordgo.File{ + Name: filepath.Base(fnameJPEG), + Reader: fin, + ContentType: "image/jpeg", + }) + } + + if _, err := s.ChannelMessageSendComplex(mc.ChannelID, &discordgo.MessageSend{ + Files: files, + Reference: &discordgo.MessageReference{ + MessageID: mc.ID, + ChannelID: mc.ChannelID, + GuildID: mc.GuildID, + FailIfNotExists: p(true), + }, + }, discordgo.WithContext(ctx)); err != nil { + s.ChannelMessageSend(mc.ChannelID, "failed to send converted images") + slog.Error("failed to send converted images", "err", err) + return + } +} |
