butterrobot/internal/shell/shell.go
Felipe M. 8801c43f92
All checks were successful
CI / goreleaser-lint (push) Successful in 10s
CI / format (push) Successful in 1m52s
Release / release (push) Successful in 5m40s
CI / lint (push) Successful in 2m31s
CI / test (push) Successful in 1m0s
CI / build (push) Successful in 4m6s
feat: add !gallerydl command to download media from links
Reply to a message containing a link with !gallerydl (or send it with a
link inline) to download the media via the gallery-dl CLI and have the
files posted back as a reply. Restricted to an allowed_users allowlist
(comma-separated, per-channel/global config); no one is allowed by
default.

- Add media support to the platform layer: model.Message.Files,
  ActionSendMedia, and Platform.SendMedia. Telegram uploads via
  multipart (sendPhoto/sendVideo/sendDocument, 50MB cap); Slack returns
  unsupported for now.
- Add internal/shell (os/exec wrapper) and internal/urlutil (URL
  extraction) helpers with tests.
- Dispatch ActionSendMedia in app and clean up the temp download dir.
- Admin config UI for allowed_users / gallery_dl_path; docs entry.
- Containerfile: base on alpine and install gallery-dl + ffmpeg (was
  scratch); release workflow sets up QEMU + Buildx for cross-arch image
  builds.
2026-07-05 20:05:57 +02:00

27 lines
767 B
Go

// Package shell is a tiny wrapper around os/exec for running external
// commands with a context (timeout/cancellation).
package shell
import (
"bytes"
"context"
"fmt"
"os/exec"
)
// Run executes name with args, using ctx for timeout/cancellation. It returns
// the combined standard output on success. On a non-zero exit (or spawn
// failure) it returns an error that includes the captured standard error.
func Run(ctx context.Context, name string, args ...string) (string, error) {
cmd := exec.CommandContext(ctx, name, args...)
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
return stdout.String(), fmt.Errorf("%s: %w: %s", name, err, stderr.String())
}
return stdout.String(), nil
}