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
This commit is contained in:
lyx0 2023-10-02 00:35:27 +02:00
parent 67e7a2e655
commit 9f75c8c31b
7 changed files with 259 additions and 20 deletions

View file

@ -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"

199
cmd/nourybot/catbox.go Normal file
View file

@ -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))
}
}

View file

@ -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

View file

@ -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())
}

View file

@ -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)")

7
go.mod
View file

@ -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 (

24
go.sum
View file

@ -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=