diff --git a/internal/actors/filesay/actor.go b/internal/actors/filesay/actor.go new file mode 100644 index 0000000..1b127e9 --- /dev/null +++ b/internal/actors/filesay/actor.go @@ -0,0 +1,115 @@ +package filesay + +import ( + "bufio" + "context" + "net/http" + "net/url" + "time" + + "github.com/go-irc/irc" + "github.com/pkg/errors" + + "github.com/Luzifer/twitch-bot/plugins" +) + +const ( + actorName = "filesay" + + httpTimeout = 5 * time.Second +) + +var ( + formatMessage plugins.MsgFormatter + send plugins.SendMessageFunc +) + +func Register(args plugins.RegistrationArguments) error { + formatMessage = args.FormatMessage + send = args.SendMessage + + args.RegisterActor(actorName, func() plugins.Actor { return &actor{} }) + + args.RegisterActorDocumentation(plugins.ActionDocumentation{ + Description: "Takes the content of an URL and pastes it to the current channel", + Name: "FileSay", + Type: actorName, + + Fields: []plugins.ActionDocumentationField{ + { + Default: "", + Description: "Source of the content to post", + Key: "source", + Name: "source", + Optional: false, + SupportTemplate: true, + Type: plugins.ActionDocumentationFieldTypeString, + }, + }, + }) + + return nil +} + +type actor struct{} + +func (a actor) Execute(c *irc.Client, m *irc.Message, r *plugins.Rule, eventData *plugins.FieldCollection, attrs *plugins.FieldCollection) (preventCooldown bool, err error) { + ptrStringEmpty := func(v string) *string { return &v }("") + + source, err := formatMessage(attrs.MustString("source", ptrStringEmpty), m, r, eventData) + if err != nil { + return false, errors.Wrap(err, "executing source template") + } + + if source == "" { + return false, errors.New("source template evaluated to empty string") + } + + if _, err := url.Parse(source); err != nil { + return false, errors.Wrap(err, "parsing URL") + } + + ctx, cancel := context.WithTimeout(context.Background(), httpTimeout) + defer cancel() + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, source, nil) + if err != nil { + return false, errors.Wrap(err, "creating HTTP request") + } + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return false, errors.Wrap(err, "executing HTTP request") + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return false, errors.Errorf("http status %d", resp.StatusCode) + } + + scanner := bufio.NewScanner(resp.Body) + for scanner.Scan() { + if err = c.WriteMessage(&irc.Message{ + Command: "PRIVMSG", + Params: []string{ + plugins.DeriveChannel(m, eventData), + scanner.Text(), + }, + }); err != nil { + return false, errors.Wrap(err, "sending message") + } + } + + return false, nil +} + +func (a actor) IsAsync() bool { return true } +func (a actor) Name() string { return actorName } + +func (a actor) Validate(attrs *plugins.FieldCollection) error { + if v, err := attrs.String("source"); err != nil || v == "" { + return errors.New("source is expected to be non-empty string") + } + + return nil +} diff --git a/plugins_core.go b/plugins_core.go index f213414..d4103f4 100644 --- a/plugins_core.go +++ b/plugins_core.go @@ -13,6 +13,7 @@ import ( "github.com/Luzifer/twitch-bot/internal/actors/ban" "github.com/Luzifer/twitch-bot/internal/actors/delay" deleteactor "github.com/Luzifer/twitch-bot/internal/actors/delete" + "github.com/Luzifer/twitch-bot/internal/actors/filesay" "github.com/Luzifer/twitch-bot/internal/actors/modchannel" "github.com/Luzifer/twitch-bot/internal/actors/nuke" "github.com/Luzifer/twitch-bot/internal/actors/punish" @@ -37,6 +38,7 @@ var ( ban.Register, delay.Register, deleteactor.Register, + filesay.Register, modchannel.Register, nuke.Register, punish.Register, diff --git a/wiki/Actors.md b/wiki/Actors.md index 90c3783..60bad5a 100644 --- a/wiki/Actors.md +++ b/wiki/Actors.md @@ -57,6 +57,19 @@ Execute external script / command skip_cooldown_on_error: false ``` +## FileSay + +Takes the content of an URL and pastes it to the current channel + +```yaml +- type: filesay + attributes: + # Source of the content to post + # Optional: false + # Type: string (Supports Templating) + source: "" +``` + ## Modify Counter Update counter values