From 9f75c8c31be7ad6f09956d11c57d22af8089b51d Mon Sep 17 00:00:00 2001 From: lyx0 Date: Mon, 2 Oct 2023 00:35:27 +0200 Subject: [PATCH] feat: add download command and upload to catbox adds a ()dl command that downloads a video using yt-dlp, then uploads the videofile to catbox and sends the catbox link --- Makefile | 4 + cmd/nourybot/catbox.go | 199 +++++++++++++++++++++++++++++++++++++++ cmd/nourybot/commands.go | 7 +- cmd/nourybot/download.go | 37 +++++--- cmd/nourybot/main.go | 1 - go.mod | 7 ++ go.sum | 24 +++++ 7 files changed, 259 insertions(+), 20 deletions(-) create mode 100644 cmd/nourybot/catbox.go diff --git a/Makefile b/Makefile index 4525bed..59ff8d5 100644 --- a/Makefile +++ b/Makefile @@ -22,3 +22,7 @@ jqprod: ./bin/${BINARY_NAME} -env="prod" | jq +prod: + cd cmd/nourybot && go build -o ${BINARY_NAME} + mv cmd/nourybot/${BINARY_NAME} ./bin/${BINARY_NAME} + ./bin/${BINARY_NAME} -env="prod" diff --git a/cmd/nourybot/catbox.go b/cmd/nourybot/catbox.go new file mode 100644 index 0000000..b075427 --- /dev/null +++ b/cmd/nourybot/catbox.go @@ -0,0 +1,199 @@ +package main + +// This whole file has been pretty much straight up copied +// from: https://github.com/wabarc/go-catbox/blob/main/catbox.go +// since I couldn't otherwise use litterbox instead. + +import ( + "bytes" + "errors" + "fmt" + "io" + "io/ioutil" + "mime/multipart" + "net/http" + "net/url" + "os" + "path/filepath" + "time" + + "github.com/wabarc/helper" +) + +const ( + //ENDPOINT = "https://catbox.moe/user/api.php" + ENDPOINT = "https://litterbox.catbox.moe/resources/internals/api.php" +) + +type catbox struct { + Client *http.Client + Userhash string +} + +func New(client *http.Client) *catbox { + if client == nil { + client = &http.Client{ + Timeout: 300 * time.Second, + } + } + + return &catbox{ + Client: client, + } +} + +// Upload file or URI to the Catbox. It returns an URL string and error. +func (cat *catbox) Upload(v ...interface{}) (string, error) { + if len(v) == 0 { + return "", fmt.Errorf(`must specify file path or byte slice`) + } + + switch t := v[0].(type) { + case string: + path := t + parse := func(s string, _ error) (string, error) { + uri, err := url.Parse(s) + if err != nil { + return "", err + } + return uri.String(), nil + } + switch { + case helper.IsURL(path): + return parse(cat.urlUpload(path)) + case helper.Exists(path): + return parse(cat.fileUpload(path)) + default: + return "", errors.New(`path invalid`) + } + case []byte: + if len(v) != 2 { + return "", fmt.Errorf(`must specify file name`) + } + return cat.rawUpload(t, v[1].(string)) + } + return "", fmt.Errorf(`unhandled`) +} + +func (cat *catbox) rawUpload(b []byte, name string) (string, error) { + r, w := io.Pipe() + m := multipart.NewWriter(w) + + go func() { + defer w.Close() + defer m.Close() + + m.WriteField("reqtype", "fileupload") + m.WriteField("userhash", cat.Userhash) + part, err := m.CreateFormFile("fileToUpload", filepath.Base(name)) + if err != nil { + return + } + if _, err = io.Copy(part, bytes.NewBuffer(b)); err != nil { + return + } + }() + req, _ := http.NewRequest(http.MethodPost, ENDPOINT, r) + req.Header.Add("Content-Type", m.FormDataContentType()) + + resp, err := cat.Client.Do(req) + if err != nil { + return "", err + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + + return string(body), nil +} + +func (cat *catbox) fileUpload(path string) (string, error) { + file, err := os.Open(path) + if err != nil { + return "", err + } + defer file.Close() + + // if size := helper.FileSize(path); size > 209715200 { + // return "", fmt.Errorf("file too large, size: %d MB", size/1024/1024) + // } + + r, w := io.Pipe() + m := multipart.NewWriter(w) + + go func() { + defer w.Close() + defer m.Close() + + m.WriteField("reqtype", "fileupload") + //m.WriteField("userhash", cat.Userhash) + m.WriteField("time", "24h") + part, err := m.CreateFormFile("fileToUpload", filepath.Base(file.Name())) + if err != nil { + return + } + + if _, err = io.Copy(part, file); err != nil { + return + } + }() + + req, _ := http.NewRequest(http.MethodPost, ENDPOINT, r) + req.Header.Add("Content-Type", m.FormDataContentType()) + + resp, err := cat.Client.Do(req) + if err != nil { + return "", err + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + + return string(body), nil +} + +func (cat *catbox) urlUpload(uri string) (string, error) { + b := new(bytes.Buffer) + w := multipart.NewWriter(b) + w.WriteField("reqtype", "urlupload") + w.WriteField("userhash", cat.Userhash) + w.WriteField("url", uri) + + req, _ := http.NewRequest(http.MethodPost, ENDPOINT, b) + req.Header.Add("Content-Type", w.FormDataContentType()) + + resp, err := cat.Client.Do(req) + if err != nil { + return "", err + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + + return string(body), nil +} + +func (cat *catbox) Delete(files ...string) error { + // TODO + return nil +} + +func (app *application) UploadCatbox(target, path string) { + app.Send(target, "Uploading to catbox... dankCircle") + + cat := New(nil) + if url, err := cat.fileUpload(path); err != nil { + app.Send(target, "Something went wrong FeelsBadMan") + } else { + app.Send(target, string(url)) + } +} diff --git a/cmd/nourybot/commands.go b/cmd/nourybot/commands.go index 0172aca..751b3de 100644 --- a/cmd/nourybot/commands.go +++ b/cmd/nourybot/commands.go @@ -84,7 +84,7 @@ func (app *application) handleCommand(message twitch.PrivateMessage) { } case "dl": - reply, _ = app.Download(target, cmdParams[1]) + app.Download(target, cmdParams[1]) case "mail": app.SendEmail("Test command used!", "This is an email test") @@ -184,12 +184,7 @@ func (app *application) handleCommand(message twitch.PrivateMessage) { app.EditUserLevel(cmdParams[3], cmdParams[4], message) } } - - // Check if the commandName exists as the "name" of a command in the database. - // if it doesnt then ignore it. - // ################## } - if reply != "" { app.Send(target, reply) return diff --git a/cmd/nourybot/download.go b/cmd/nourybot/download.go index 39e6d99..e8275a8 100644 --- a/cmd/nourybot/download.go +++ b/cmd/nourybot/download.go @@ -2,37 +2,48 @@ package main import ( "context" + "fmt" "io" "os" - "os/exec" + "github.com/google/uuid" "github.com/wader/goutubedl" ) -func (app *application) Download(channel, link string) (string, error) { +func (app *application) Download(target, link string) { goutubedl.Path = "yt-dlp" - app.Send(channel, "dankCircle") + app.Send(target, "Downloading... dankCircle") result, err := goutubedl.New(context.Background(), link, goutubedl.Options{}) if err != nil { - app.Log.Fatal(err) + app.Log.Errorln(err) } + rExt := result.Info.Ext downloadResult, err := result.Download(context.Background(), "best") if err != nil { - app.Log.Fatal(err) + app.Log.Errorln(err) } + app.Send(target, "Downloaded..") defer downloadResult.Close() - f, err := os.Create("output.mp4") + fn, err := uuid.NewUUID() if err != nil { - app.Log.Fatal(err) + app.Log.Errorln(err) + } + f, err := os.Create(fmt.Sprintf("%s.%s", fn, rExt)) + app.Send(target, fmt.Sprintf("Filename: %s.%s", fn, rExt)) + + if err != nil { + app.Log.Errorln(err) } defer f.Close() - io.Copy(f, downloadResult) - - out, err := exec.Command("curl", "-L", "-F", "file=@output.mp4", "i.yaf.ee/upload").Output() - if err != nil { - app.Log.Fatal(err) + if _, err = io.Copy(f, downloadResult); err != nil { + app.Log.Errorln(err) } - return string(out), nil + + app.UploadCatbox(target, fmt.Sprintf("%s.%s", fn, rExt)) + + //os.Remove(fmt.Sprintf("%s.mp4", fn)) + + //app.TwitchClient.Say(channel, b.String()) } diff --git a/cmd/nourybot/main.go b/cmd/nourybot/main.go index 1732f20..5f596a1 100644 --- a/cmd/nourybot/main.go +++ b/cmd/nourybot/main.go @@ -44,7 +44,6 @@ type application struct { } var envFlag string -var ctx = context.Background() func init() { flag.StringVar(&envFlag, "env", "dev", "database connection to use: (dev/prod)") diff --git a/go.mod b/go.mod index 49b6599..a8e4504 100644 --- a/go.mod +++ b/go.mod @@ -14,10 +14,17 @@ require ( ) require ( + github.com/google/uuid v1.3.1 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/wabarc/go-catbox v0.1.0 // indirect + github.com/wabarc/helper v0.0.0-20210718171053-59c70d0b20c2 // indirect github.com/wader/goutubedl v0.0.0-20230924165737-427b7fa536e6 // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect + golang.org/x/net v0.0.0-20210716203947-853a461950ff // indirect + golang.org/x/text v0.3.6 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect + mvdan.cc/xurls/v2 v2.2.0 // indirect ) require ( diff --git a/go.sum b/go.sum index fee0156..f4446c0 100644 --- a/go.sum +++ b/go.sum @@ -13,10 +13,15 @@ github.com/gempir/go-twitch-irc/v4 v4.0.0/go.mod h1:QsOMMAk470uxQ7EYD9GJBGAVqM/j github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c= github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/jakecoffman/cron v0.0.0-20190106200828-7e2009c226a5 h1:kCvm3G3u+eTRbjfLPyfsfznJtraYEfZer/UvQ6CaQhI= github.com/jakecoffman/cron v0.0.0-20190106200828-7e2009c226a5/go.mod h1:6DM2KNNK69jRu0lAHmYK9LYxmqpNjYHOaNp/ZxttD4U= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= @@ -29,6 +34,7 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc= github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU= @@ -37,6 +43,10 @@ github.com/shkh/lastfm-go v0.0.0-20191215035245-89a801c244e0/go.mod h1:n3nudMl17 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/wabarc/go-catbox v0.1.0 h1:/UhV9md3MJrjZtm+EToSyFjawXgPiHSExLNRqsWNisg= +github.com/wabarc/go-catbox v0.1.0/go.mod h1:Zjs9Y55f2WOwGWwmKSCrUuMfwh+nDktkjub9jgHq4CQ= +github.com/wabarc/helper v0.0.0-20210718171053-59c70d0b20c2 h1:6rMZse2rdD7N6GxHRZqHlkSptBWh/Vf9aHiFVQjlQNo= +github.com/wabarc/helper v0.0.0-20210718171053-59c70d0b20c2/go.mod h1:uS6mimKlWkGvEZXkJ6JoW7LYnnB2JP6dLU9q7pgDaWQ= github.com/wader/goutubedl v0.0.0-20230924165737-427b7fa536e6 h1:KHJV3fnnKsdWdGu5IKrDAA0Oa5RzGwrJpfx+bvVAjLA= github.com/wader/goutubedl v0.0.0-20230924165737-427b7fa536e6/go.mod h1:5KXd5tImdbmz4JoVhePtbIokCwAfEhUVVx3WLHmjYuw= github.com/wader/osleaktest v0.0.0-20191111175233-f643b0fed071/go.mod h1:XD6emOFPHVzb0+qQpiNOdPL2XZ0SRUM0N5JHuq6OmXo= @@ -47,12 +57,26 @@ go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210716203947-853a461950ff h1:j2EK/QoxYNBsXI4R7fQkkRUk8y6wnOBI+6hgPdP/6Ds= +golang.org/x/net v0.0.0-20210716203947-853a461950ff/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +mvdan.cc/xurls/v2 v2.2.0 h1:NSZPykBXJFCetGZykLAxaL6SIpvbVy/UFEniIfHAa8A= +mvdan.cc/xurls/v2 v2.2.0/go.mod h1:EV1RMtya9D6G5DMYPGD8zTQzaHet6Jh8gFlRgGRJeO8=