diff --git a/cmd/nourybot/commands.go b/cmd/nourybot/commands.go index f5e8231..3b73f5a 100644 --- a/cmd/nourybot/commands.go +++ b/cmd/nourybot/commands.go @@ -84,10 +84,10 @@ func (app *application) handleCommand(message twitch.PrivateMessage) { } case "cb": - go commands.DownloadCatbox(target, cmdParams[1], app.TwitchClient, app.Log) + go commands.NewDownload("catbox", target, cmdParams[1], app.TwitchClient, app.Log) case "dl": - go commands.Download(target, cmdParams[1], fileUploaderURL, app.TwitchClient, app.Log) + go commands.NewDownload("custom", target, cmdParams[1], app.TwitchClient, app.Log) case "mail": app.SendEmail("Test command used!", "This is an email test") diff --git a/internal/commands/catbox.go b/internal/commands/catbox.go deleted file mode 100644 index 9562753..0000000 --- a/internal/commands/catbox.go +++ /dev/null @@ -1,256 +0,0 @@ -// The whole catbox upload functionality has been copied from -// here so that I could use it with litterbox: -// https://github.com/wabarc/go-catbox/blob/main/catbox.go <3 -// -// Copyright 2021 Wayback Archiver. All rights reserved. -// Use of this source code is governed by the MIT -// license that can be found in the LICENSE file. - -package commands - -import ( - "bytes" - "context" - "fmt" - "io" - "io/ioutil" - "mime/multipart" - "net/http" - "net/url" - "os" - "path/filepath" - "time" - - "github.com/gempir/go-twitch-irc/v4" - "github.com/google/uuid" - "github.com/pkg/errors" - "github.com/wabarc/helper" - "github.com/wader/goutubedl" - "go.uber.org/zap" -) - -const ( - ENDPOINT = "https://litterbox.catbox.moe/resources/internals/api.php" -) - -type Catbox struct { - Client *http.Client - Time string - Userhash string - TwitchClient *twitch.Client - Log *zap.SugaredLogger -} - -func NewCat(twitchClient *twitch.Client, log *zap.SugaredLogger) *Catbox { - client := &http.Client{ - Timeout: 300 * time.Second, - } - - return &Catbox{ - Client: client, - Time: "24h", - TwitchClient: twitchClient, - Log: log, - } -} - -func DownloadCatbox(target, link string, tc *twitch.Client, log *zap.SugaredLogger) (reply string) { - cat := NewCat(tc, log) - - go cat.downloadCatbox(target, link) - return "" -} - -func (cat *Catbox) downloadCatbox(target, link string) { - goutubedl.Path = "yt-dlp" - var fileName string - - cat.TwitchClient.Say(target, "Downloading... dankCircle") - result, err := goutubedl.New(context.Background(), link, goutubedl.Options{}) - if err != nil { - cat.Log.Errorln(err) - } - - // I don't know why but I need to set it to mp4, otherwise if - // I use `result.Into.Ext` catbox won't play the video in the - // browser and say this message: - // `No video with supported format and MIME type found.` - rExt := "mp4" - - downloadResult, err := result.Download(context.Background(), "best") - if err != nil { - cat.Log.Errorln(err) - } - cat.TwitchClient.Say(target, "Downloaded.") - uuidFilename, err := uuid.NewUUID() - fileName = fmt.Sprintf("%s.%s", uuidFilename, rExt) - if err != nil { - cat.Log.Errorln(err) - } - f, err := os.Create(fileName) - cat.TwitchClient.Say(target, fmt.Sprintf("Filename: %s", fileName)) - - if err != nil { - cat.Log.Errorln(err) - } - defer f.Close() - if _, err = io.Copy(f, downloadResult); err != nil { - cat.Log.Errorln(err) - } - - downloadResult.Close() - f.Close() - - if url, err := cat.fileUpload(fileName); err != nil { - cat.TwitchClient.Say(target, fmt.Sprintf("Something went wrong FeelsBadMan: %v", err)) - } else { - cat.TwitchClient.Say(target, url) - } -} - -// 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("time", cat.Time) - //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) { - defer os.Remove(path) - 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("time", cat.Time) - m.WriteField("userhash", cat.Userhash) - 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 -} diff --git a/internal/commands/download.go b/internal/commands/download.go index b1e5228..7238a10 100644 --- a/internal/commands/download.go +++ b/internal/commands/download.go @@ -4,10 +4,7 @@ import ( "context" "fmt" "io" - "mime/multipart" - "net/http" "os" - "time" "github.com/gempir/go-twitch-irc/v4" "github.com/google/uuid" @@ -15,28 +12,29 @@ import ( "go.uber.org/zap" ) -type downloader struct { - twitchClient *twitch.Client +type Downloader struct { + TwitchClient *twitch.Client Log *zap.SugaredLogger - URL string } -func Download(target, link, fileUploadURL string, tc *twitch.Client, log *zap.SugaredLogger) (reply string) { - dloader := &downloader{ +func NewDownload(destination, target, link string, tc *twitch.Client, log *zap.SugaredLogger) { + dl := &Downloader{ + TwitchClient: tc, Log: log, - twitchClient: tc, - URL: fileUploadURL, } - go dloader.dlxd(target, link) - - return "" + switch destination { + case "catbox": + dl.CatboxDownload(target, link) + case "custom": + dl.CustomDownload(target, link) + } } -func (dl *downloader) dlxd(target, link string) { +func (dl *Downloader) CustomDownload(target, link string) { goutubedl.Path = "yt-dlp" - dl.twitchClient.Say(target, "Downloading... dankCircle") + dl.TwitchClient.Say(target, "[custom] Downloading... dankCircle") result, err := goutubedl.New(context.Background(), link, goutubedl.Options{}) if err != nil { dl.Log.Errorln(err) @@ -46,13 +44,14 @@ func (dl *downloader) dlxd(target, link string) { if err != nil { dl.Log.Errorln(err) } - dl.twitchClient.Say(target, "Downloaded.") - fn, err := uuid.NewUUID() + dl.TwitchClient.Say(target, "Downloaded.") + uuidFilename, err := uuid.NewUUID() if err != nil { dl.Log.Errorln(err) } - f, err := os.Create(fmt.Sprintf("%s.%s", fn, rExt)) - dl.twitchClient.Say(target, fmt.Sprintf("Filename: %s.%s", fn, rExt)) + fileName := fmt.Sprintf("%s.%s", uuidFilename, rExt) + f, err := os.Create(fileName) + dl.TwitchClient.Say(target, fmt.Sprintf("Filename: %s", fileName)) if err != nil { dl.Log.Errorln(err) @@ -68,82 +67,49 @@ func (dl *downloader) dlxd(target, link string) { // dl.twitchClient.Say(target, "ResidentSleeper ..") // time.Sleep(duration) - dl.upload(target, fmt.Sprintf("%s.%s", fn, rExt)) + go NewUpload("custom", fileName, target, dl.TwitchClient, dl.Log) } -func (dl *downloader) upload(target, path string) { - dl.twitchClient.Say(target, "Uploading... dankCircle") - pr, pw := io.Pipe() - form := multipart.NewWriter(pw) +func (dl *Downloader) CatboxDownload(target, link string) { + goutubedl.Path = "yt-dlp" + var fileName string - go func() { - defer pw.Close() - - err := form.WriteField("name", "xd") - if err != nil { - dl.twitchClient.Say(target, fmt.Sprintf("Something went wrong FeelsBadMan: %q", err)) - os.Remove(path) - return - } - - file, err := os.Open(path) // path to image file - if err != nil { - dl.twitchClient.Say(target, fmt.Sprintf("Something went wrong FeelsBadMan: %q", err)) - os.Remove(path) - return - } - - w, err := form.CreateFormFile("file", path) - if err != nil { - dl.twitchClient.Say(target, fmt.Sprintf("Something went wrong FeelsBadMan: %q", err)) - os.Remove(path) - return - } - - _, err = io.Copy(w, file) - if err != nil { - dl.twitchClient.Say(target, fmt.Sprintf("Something went wrong FeelsBadMan: %q", err)) - os.Remove(path) - return - } - - form.Close() - }() - - req, err := http.NewRequest(http.MethodPost, dl.URL, pr) + dl.TwitchClient.Say(target, "Downloading... dankCircle") + result, err := goutubedl.New(context.Background(), link, goutubedl.Options{}) if err != nil { - dl.twitchClient.Say(target, fmt.Sprintf("Something went wrong FeelsBadMan: %q", err)) - os.Remove(path) - return + dl.Log.Errorln(err) } - req.Header.Set("Content-Type", form.FormDataContentType()) - httpClient := http.Client{ - Timeout: 300 * time.Second, - } - resp, err := httpClient.Do(req) + // I don't know why but I need to set it to mp4, otherwise if + // I use `result.Into.Ext` catbox won't play the video in the + // browser and say this message: + // `No video with supported format and MIME type found.` + rExt := "mp4" + + downloadResult, err := result.Download(context.Background(), "best") if err != nil { - dl.twitchClient.Say(target, fmt.Sprintf("Something went wrong FeelsBadMan: %q", err)) - os.Remove(path) - dl.Log.Errorln("Error while sending HTTP request:", err) - - return + dl.Log.Errorln(err) } - defer resp.Body.Close() - dl.twitchClient.Say(target, "Uploaded PogChamp") - - body, err := io.ReadAll(resp.Body) + dl.TwitchClient.Say(target, "Downloaded.") + uuidFilename, err := uuid.NewUUID() if err != nil { - dl.twitchClient.Say(target, fmt.Sprintf("Something went wrong FeelsBadMan: %q", err)) - os.Remove(path) - dl.Log.Errorln("Error while reading response:", err) - return + dl.Log.Errorln(err) + } + fileName = fmt.Sprintf("%s.%s", uuidFilename, rExt) + f, err := os.Create(fileName) + dl.TwitchClient.Say(target, fmt.Sprintf("Filename: %s", fileName)) + + if err != nil { + dl.Log.Errorln(err) + } + defer f.Close() + if _, err = io.Copy(f, downloadResult); err != nil { + dl.Log.Errorln(err) } - var reply = string(body[:]) + downloadResult.Close() + f.Close() - dl.twitchClient.Say(target, fmt.Sprintf("Removing file: %s", path)) - os.Remove(path) - dl.twitchClient.Say(target, reply) + go NewUpload("catbox", fileName, target, dl.TwitchClient, dl.Log) } diff --git a/internal/commands/upload.go b/internal/commands/upload.go new file mode 100644 index 0000000..c991906 --- /dev/null +++ b/internal/commands/upload.go @@ -0,0 +1,187 @@ +// The whole catbox upload functionality has been copied from +// here so that I could use it with litterbox: +// https://github.com/wabarc/go-catbox/blob/main/catbox.go <3 +// +// Copyright 2021 Wayback Archiver. All rights reserved. +// Use of this source code is governed by the MIT +// license that can be found in the LICENSE file. + +package commands + +import ( + "fmt" + "io" + "io/ioutil" + "mime/multipart" + "net/http" + "os" + "path/filepath" + "time" + + "github.com/gempir/go-twitch-irc/v4" + "go.uber.org/zap" +) + +const ( + CUSTOM_ENDPOINT = "https://i.yaf.ee/upload" + CATBOX_ENDPOINT = "https://litterbox.catbox.moe/resources/internals/api.php" +) + +type Uploader struct { + Client *http.Client + Time string + Userhash string + TwitchClient *twitch.Client + Log *zap.SugaredLogger +} + +func NewUpload(destination, fileName, target string, twitchClient *twitch.Client, log *zap.SugaredLogger) { + client := &http.Client{ + Timeout: 300 * time.Second, + } + + ul := &Uploader{ + Client: client, + Time: "24h", + TwitchClient: twitchClient, + Log: log, + } + + switch destination { + case "catbox": + go ul.CatboxUpload(target, fileName) + case "custom": + go ul.CustomUpload(target, fileName) + + } +} + +func (ul *Uploader) CatboxUpload(target, fileName string) { + defer os.Remove(fileName) + file, err := os.Open(fileName) + if err != nil { + ul.TwitchClient.Say(target, fmt.Sprintf("Something went wrong FeelsBadMan: %q", err)) + return + } + defer file.Close() + + // if size := helper.FileSize(fileName); 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("time", ul.Time) + part, err := m.CreateFormFile("fileToUpload", filepath.Base(file.Name())) + if err != nil { + ul.TwitchClient.Say(target, fmt.Sprintf("Something went wrong FeelsBadMan: %q", err)) + return + } + + if _, err = io.Copy(part, file); err != nil { + return + } + }() + + req, _ := http.NewRequest(http.MethodPost, CATBOX_ENDPOINT, r) + req.Header.Add("Content-Type", m.FormDataContentType()) + + resp, err := ul.Client.Do(req) + if err != nil { + ul.TwitchClient.Say(target, fmt.Sprintf("Something went wrong FeelsBadMan: %q", err)) + return + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + ul.TwitchClient.Say(target, fmt.Sprintf("Something went wrong FeelsBadMan: %q", err)) + return + } + + reply := string(body) + ul.TwitchClient.Say(target, fmt.Sprintf("Removing file: %s", fileName)) + ul.TwitchClient.Say(target, reply) +} + +func (ul *Uploader) CustomUpload(target, path string) { + defer os.Remove(path) + ul.TwitchClient.Say(target, "Uploading... dankCircle") + pr, pw := io.Pipe() + form := multipart.NewWriter(pw) + + go func() { + defer pw.Close() + + err := form.WriteField("name", "xd") + if err != nil { + ul.TwitchClient.Say(target, fmt.Sprintf("Something went wrong FeelsBadMan: %q", err)) + os.Remove(path) + return + } + + file, err := os.Open(path) // path to image file + if err != nil { + ul.TwitchClient.Say(target, fmt.Sprintf("Something went wrong FeelsBadMan: %q", err)) + os.Remove(path) + return + } + + w, err := form.CreateFormFile("file", path) + if err != nil { + ul.TwitchClient.Say(target, fmt.Sprintf("Something went wrong FeelsBadMan: %q", err)) + os.Remove(path) + return + } + + _, err = io.Copy(w, file) + if err != nil { + ul.TwitchClient.Say(target, fmt.Sprintf("Something went wrong FeelsBadMan: %q", err)) + os.Remove(path) + return + } + + form.Close() + }() + + req, err := http.NewRequest(http.MethodPost, CUSTOM_ENDPOINT, pr) + if err != nil { + ul.TwitchClient.Say(target, fmt.Sprintf("Something went wrong FeelsBadMan: %q", err)) + os.Remove(path) + return + } + req.Header.Set("Content-Type", form.FormDataContentType()) + + httpClient := http.Client{ + Timeout: 300 * time.Second, + } + resp, err := httpClient.Do(req) + if err != nil { + ul.TwitchClient.Say(target, fmt.Sprintf("Something went wrong FeelsBadMan: %q", err)) + os.Remove(path) + ul.Log.Errorln("Error while sending HTTP request:", err) + + return + } + defer resp.Body.Close() + ul.TwitchClient.Say(target, "Uploaded PogChamp") + + body, err := io.ReadAll(resp.Body) + if err != nil { + ul.TwitchClient.Say(target, fmt.Sprintf("Something went wrong FeelsBadMan: %q", err)) + os.Remove(path) + ul.Log.Errorln("Error while reading response:", err) + return + } + + var reply = string(body[:]) + + ul.TwitchClient.Say(target, fmt.Sprintf("Removing file: %s", path)) + ul.TwitchClient.Say(target, reply) +}