From c0f111b08ef93f0d60a1e93ec2b1ff2375596403 Mon Sep 17 00:00:00 2001 From: XangelMusic Date: Tue, 4 Jun 2024 02:28:30 +0800 Subject: [PATCH 01/30] refactor: Organized regex patterns of providers --- artworks/artstation/artstation.go | 4 +--- artworks/deviant/deviant.go | 2 +- artworks/pixiv/pixiv.go | 8 +++----- artworks/twitter/fxtwitter.go | 16 +++++++++------- artworks/twitter/matcher.go | 8 +++++--- artworks/twitter/twitter.go | 8 +++++++- 6 files changed, 26 insertions(+), 20 deletions(-) diff --git a/artworks/artstation/artstation.go b/artworks/artstation/artstation.go index 33d816e..79acf50 100644 --- a/artworks/artstation/artstation.go +++ b/artworks/artstation/artstation.go @@ -71,10 +71,8 @@ type Category struct { } func New() artworks.Provider { - r := regexp.MustCompile(`(?i)https:\/\/(?:www\.)?artstation\.com\/artwork\/([\w\-]+)`) - return &Artstation{ - regex: r, + regex: regexp.MustCompile(`(?i)https://(?:www\.)?artstation\.com/artwork/([\w\-]+)`), } } diff --git a/artworks/deviant/deviant.go b/artworks/deviant/deviant.go index 87f027d..35b7ea5 100644 --- a/artworks/deviant/deviant.go +++ b/artworks/deviant/deviant.go @@ -65,7 +65,7 @@ type deviantEmbed struct { func New() artworks.Provider { return &DeviantArt{ - regex: regexp.MustCompile(`(?i)https:\/\/(?:www\.)?deviantart\.com\/[\w]+\/art\/([\w\-]+)`), + regex: regexp.MustCompile(`(?i)https://(?:www\.)?deviantart\.com/[\w]+/art/([\w\-]+)`), } } diff --git a/artworks/pixiv/pixiv.go b/artworks/pixiv/pixiv.go index acfa4e3..34ed93e 100644 --- a/artworks/pixiv/pixiv.go +++ b/artworks/pixiv/pixiv.go @@ -16,13 +16,10 @@ import ( "github.com/everpcpc/pixiv" ) -var regex = regexp.MustCompile( - `(?i)http(?:s)?:\/\/(?:www\.)?pixiv\.net\/(?:en\/)?(?:artworks\/|member_illust\.php\?)(?:mode=medium\&)?(?:illust_id=)?([0-9]+)`, -) - type Pixiv struct { app *pixiv.AppPixivAPI proxyHost string + regex *regexp.Regexp } type Artwork struct { @@ -60,11 +57,12 @@ func New(proxyHost, authToken, refreshToken string) (artworks.Provider, error) { return &Pixiv{ app: pixiv.NewApp(), proxyHost: proxyHost, + regex: regexp.MustCompile(`(?i)https?://(?:www\.)?pixiv\.net/(?:en/)?(?:artworks/|member_illust\.php\?)(?:mode=medium&)?(?:illust_id=)?([0-9]+)`), }, nil } func (p *Pixiv) Match(s string) (string, bool) { - res := regex.FindStringSubmatch(s) + res := p.regex.FindStringSubmatch(s) if res == nil { return "", false } diff --git a/artworks/twitter/fxtwitter.go b/artworks/twitter/fxtwitter.go index 06745c0..e6d477f 100644 --- a/artworks/twitter/fxtwitter.go +++ b/artworks/twitter/fxtwitter.go @@ -12,11 +12,10 @@ import ( "github.com/VTGare/boe-tea-go/internal/arrays" ) -var nonAlphanumericRegex = regexp.MustCompile(`[^\p{L}\p{N} -]+`) - type fxTwitter struct { twitterMatcher - client *http.Client + client *http.Client + nonAlphanumericRegex *regexp.Regexp } type fxTwitterResponse struct { @@ -54,10 +53,13 @@ type fxTwitterResponse struct { } `json:"tweet,omitempty"` } -func newFxTwitter() artworks.Provider { +func newFxTwitter(re *regexp.Regexp) artworks.Provider { return &fxTwitter{ - twitterMatcher: twitterMatcher{}, - client: &http.Client{}, + client: &http.Client{}, + nonAlphanumericRegex: regexp.MustCompile(`[^\p{L}\p{N} -]+`), + twitterMatcher: twitterMatcher{ + regex: re, + }, } } @@ -127,7 +129,7 @@ func (fxt *fxTwitter) Find(id string) (artworks.Artwork, error) { } artwork.AIGenerated = artworks.IsAIGenerated(arrays.Map(strings.Fields(artwork.Content), func(s string) string { - return nonAlphanumericRegex.ReplaceAllString(s, "") + return fxt.nonAlphanumericRegex.ReplaceAllString(s, "") })...) return artwork, nil diff --git a/artworks/twitter/matcher.go b/artworks/twitter/matcher.go index 90b3c91..60e8e4f 100644 --- a/artworks/twitter/matcher.go +++ b/artworks/twitter/matcher.go @@ -9,15 +9,17 @@ import ( "github.com/VTGare/boe-tea-go/store" ) -type twitterMatcher struct{} +type twitterMatcher struct { + regex *regexp.Regexp +} -func (twitterMatcher) Match(s string) (string, bool) { +func (t twitterMatcher) Match(s string) (string, bool) { u, err := url.ParseRequestURI(s) if err != nil { return "", false } - if ok, _ := regexp.MatchString("^(?:mobile\\.)?(?:(?:fix(?:up|v))?x|(?:[fv]x)?twitter)\\.com$", u.Host); !ok { + if ok := t.regex.MatchString(u.Host); !ok { return "", false } diff --git a/artworks/twitter/twitter.go b/artworks/twitter/twitter.go index cb6f84f..f8bdbf4 100644 --- a/artworks/twitter/twitter.go +++ b/artworks/twitter/twitter.go @@ -7,6 +7,7 @@ import ( "io" "net/http" "net/url" + "regexp" "strconv" "strings" "time" @@ -51,8 +52,13 @@ type Video struct { } func New() artworks.Provider { + re := regexp.MustCompile(`^(?:mobile\\.)?(?:(?:fix(?:up|v))?x|(?:[fv]x)?twitter)\\.com$`) + return &Twitter{ - providers: []artworks.Provider{newFxTwitter()}, + providers: []artworks.Provider{newFxTwitter(re)}, + twitterMatcher: twitterMatcher{ + regex: re, + }, } } From 44add1d19c1133f566cb5574f61793c16f09b5ca Mon Sep 17 00:00:00 2001 From: XangelMusic Date: Tue, 4 Jun 2024 17:51:39 +0800 Subject: [PATCH 02/30] refactor: Find, NewError functions --- artworks/artstation/artstation.go | 37 ++++---- artworks/artworks.go | 14 ++- artworks/deviant/deviant.go | 75 +++++++--------- artworks/pixiv/pixiv.go | 145 ++++++++++++++---------------- artworks/twitter/twitter.go | 38 ++++---- 5 files changed, 148 insertions(+), 161 deletions(-) diff --git a/artworks/artstation/artstation.go b/artworks/artstation/artstation.go index 79acf50..6c4d754 100644 --- a/artworks/artstation/artstation.go +++ b/artworks/artstation/artstation.go @@ -77,32 +77,25 @@ func New() artworks.Provider { } func (as *Artstation) Find(id string) (artworks.Artwork, error) { - artwork, err := as._find(id) - if err != nil { - return nil, artworks.NewError(as, err) - } - - return artwork, nil -} - -func (as *Artstation) _find(id string) (artworks.Artwork, error) { - reqURL := fmt.Sprintf("https://www.artstation.com/projects/%v.json", id) - resp, err := http.Get(reqURL) - if err != nil { - return nil, err - } + return artworks.NewError(as, func() (artworks.Artwork, error) { + reqURL := fmt.Sprintf("https://www.artstation.com/projects/%v.json", id) + resp, err := http.Get(reqURL) + if err != nil { + return nil, err + } - defer resp.Body.Close() + defer resp.Body.Close() - res := &ArtstationResponse{} - err = json.NewDecoder(resp.Body).Decode(res) - if err != nil { - return nil, err - } + res := &ArtstationResponse{} + err = json.NewDecoder(resp.Body).Decode(res) + if err != nil { + return nil, err + } - res.AIGenerated = artworks.IsAIGenerated(res.Tags...) + res.AIGenerated = artworks.IsAIGenerated(res.Tags...) - return res, nil + return res, nil + }) } func (as *Artstation) Match(url string) (string, bool) { diff --git a/artworks/artworks.go b/artworks/artworks.go index c5273af..f60e504 100644 --- a/artworks/artworks.go +++ b/artworks/artworks.go @@ -36,11 +36,17 @@ func (e *Error) Unwrap() error { return e.cause } -func NewError(p Provider, err error) error { - return &Error{ - provider: fmt.Sprintf("%T", p), - cause: err, +func NewError(p Provider, find func() (Artwork, error)) (Artwork, error) { + artwork, err := find() + + if err != nil { + return nil, &Error{ + provider: fmt.Sprintf("%T", p), + cause: err, + } } + + return artwork, nil } // Common errors diff --git a/artworks/deviant/deviant.go b/artworks/deviant/deviant.go index 35b7ea5..329b91f 100644 --- a/artworks/deviant/deviant.go +++ b/artworks/deviant/deviant.go @@ -70,47 +70,40 @@ func New() artworks.Provider { } func (d *DeviantArt) Find(id string) (artworks.Artwork, error) { - artwork, err := d._find(id) - if err != nil { - return nil, artworks.NewError(d, err) - } - - return artwork, nil -} - -func (d *DeviantArt) _find(id string) (artworks.Artwork, error) { - reqURL := "https://backend.deviantart.com/oembed?url=" + url.QueryEscape("deviantart.com/art/"+id) - resp, err := http.Get(reqURL) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - var res deviantEmbed - err = json.NewDecoder(resp.Body).Decode(&res) - if err != nil { - return nil, err - } - - artwork := &Artwork{ - Title: res.Title, - Author: &Author{ - Name: res.AuthorName, - URL: res.AuthorURL, - }, - ImageURL: res.URL, - ThumbnailURL: res.ThumbnailURL, - Tags: strings.Split(res.Tags, ", "), - Views: res.Community.Statistics.Attributes.Views, - Favorites: res.Community.Statistics.Attributes.Favorites, - Comments: res.Community.Statistics.Attributes.Comments, - CreatedAt: res.Pubdate, - url: res.AuthorURL + "/art/" + id, - } - - artwork.AIGenerated = artworks.IsAIGenerated(artwork.Tags...) - - return artwork, nil + return artworks.NewError(d, func() (artworks.Artwork, error) { + reqURL := "https://backend.deviantart.com/oembed?url=" + url.QueryEscape("deviantart.com/art/"+id) + resp, err := http.Get(reqURL) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var res deviantEmbed + err = json.NewDecoder(resp.Body).Decode(&res) + if err != nil { + return nil, err + } + + artwork := &Artwork{ + Title: res.Title, + Author: &Author{ + Name: res.AuthorName, + URL: res.AuthorURL, + }, + ImageURL: res.URL, + ThumbnailURL: res.ThumbnailURL, + Tags: strings.Split(res.Tags, ", "), + Views: res.Community.Statistics.Attributes.Views, + Favorites: res.Community.Statistics.Attributes.Favorites, + Comments: res.Community.Statistics.Attributes.Comments, + CreatedAt: res.Pubdate, + url: res.AuthorURL + "/art/" + id, + } + + artwork.AIGenerated = artworks.IsAIGenerated(artwork.Tags...) + + return artwork, nil + }) } func (d *DeviantArt) Match(s string) (string, bool) { diff --git a/artworks/pixiv/pixiv.go b/artworks/pixiv/pixiv.go index 34ed93e..80594d8 100644 --- a/artworks/pixiv/pixiv.go +++ b/artworks/pixiv/pixiv.go @@ -71,103 +71,96 @@ func (p *Pixiv) Match(s string) (string, bool) { } func (p *Pixiv) Find(id string) (artworks.Artwork, error) { - artwork, err := p._find(id) - if err != nil { - return nil, artworks.NewError(p, err) - } - - return artwork, nil -} + return artworks.NewError(p, func() (artworks.Artwork, error) { + i, err := strconv.ParseUint(id, 10, 64) + if err != nil { + return nil, err + } -func (p *Pixiv) _find(id string) (artworks.Artwork, error) { - i, err := strconv.ParseUint(id, 10, 64) - if err != nil { - return nil, err - } + illust, err := p.app.IllustDetail(i) + if err != nil { + return nil, err + } - illust, err := p.app.IllustDetail(i) - if err != nil { - return nil, err - } + if illust.ID == 0 { + return nil, artworks.ErrArtworkNotFound + } - if illust.ID == 0 { - return nil, artworks.ErrArtworkNotFound - } + author := "" + if illust.User != nil { + author = illust.User.Name + } else { + author = "Unknown" + } - author := "" - if illust.User != nil { - author = illust.User.Name - } else { - author = "Unknown" - } + tags := make([]string, 0) + nsfw := false + for _, tag := range illust.Tags { + if tag.Name == "R-18" { + nsfw = true + } - tags := make([]string, 0) - nsfw := false - for _, tag := range illust.Tags { - if tag.Name == "R-18" { - nsfw = true + if tag.TranslatedName != "" { + tags = append(tags, tag.TranslatedName) + } else { + tags = append(tags, tag.Name) + } } - if tag.TranslatedName != "" { - tags = append(tags, tag.TranslatedName) - } else { - tags = append(tags, tag.Name) + images := make([]*Image, 0, illust.PageCount) + if page := illust.MetaSinglePage; page != nil { + if page.OriginalImageURL != "" { + img := &Image{ + Original: page.OriginalImageURL, + Preview: illust.Images.Medium, + } + + images = append(images, img) + } } - } - images := make([]*Image, 0, illust.PageCount) - if page := illust.MetaSinglePage; page != nil { - if page.OriginalImageURL != "" { + for _, page := range illust.MetaPages { img := &Image{ - Original: page.OriginalImageURL, - Preview: illust.Images.Medium, + Original: page.Images.Original, + Preview: page.Images.Large, } images = append(images, img) } - } - for _, page := range illust.MetaPages { - img := &Image{ - Original: page.Images.Original, - Preview: page.Images.Large, + artwork := &Artwork{ + ID: id, + url: "https://www.pixiv.net/en/artworks/" + id, + Title: illust.Title, + Author: author, + Tags: tags, + Images: images, + NSFW: nsfw, + Type: illust.Type, + Pages: illust.PageCount, + Likes: illust.TotalBookmarks, + CreatedAt: illust.CreateDate, + + proxy: p.proxyHost, } - images = append(images, img) - } - - artwork := &Artwork{ - ID: id, - url: "https://www.pixiv.net/en/artworks/" + id, - Title: illust.Title, - Author: author, - Tags: tags, - Images: images, - NSFW: nsfw, - Type: illust.Type, - Pages: illust.PageCount, - Likes: illust.TotalBookmarks, - CreatedAt: illust.CreateDate, - - proxy: p.proxyHost, - } - - errImages := []string{ - "limit_sanity_level_360.png", - "limit_unknown_360.png", - } + errImages := []string{ + "limit_sanity_level_360.png", + "limit_unknown_360.png", + } - for _, img := range errImages { - if artwork.Images[0].Original == fmt.Sprintf("https://s.pximg.net/common/images/%s", img) { - return nil, artworks.ErrRateLimited + for _, img := range errImages { + if artwork.Images[0].Original == fmt.Sprintf("https://s.pximg.net/common/images/%s", img) { + return nil, artworks.ErrRateLimited + } } - } - if illust.IllustAIType == pixiv.IllustAITypeAIGenerated { - artwork.AIGenerated = true - } + if illust.IllustAIType == pixiv.IllustAITypeAIGenerated { + artwork.AIGenerated = true + } - return artwork, nil + return artwork, nil + }) } func (p *Pixiv) Enabled(g *store.Guild) bool { diff --git a/artworks/twitter/twitter.go b/artworks/twitter/twitter.go index f8bdbf4..f9347d7 100644 --- a/artworks/twitter/twitter.go +++ b/artworks/twitter/twitter.go @@ -63,27 +63,29 @@ func New() artworks.Provider { } func (t *Twitter) Find(id string) (artworks.Artwork, error) { - var ( - artwork artworks.Artwork - errs []error - ) - - for _, provider := range t.providers { - var err error - artwork, err = provider.Find(id) - if errors.Is(err, ErrTweetNotFound) || errors.Is(err, ErrPrivateAccount) { - return nil, artworks.NewError(t, err) - } + return artworks.NewError(t, func() (artworks.Artwork, error) { + var ( + artwork artworks.Artwork + errs []error + ) + + for _, provider := range t.providers { + var err error + artwork, err = provider.Find(id) + if errors.Is(err, ErrTweetNotFound) || errors.Is(err, ErrPrivateAccount) { + return nil, err + } - if err != nil { - errs = append(errs, err) - continue - } + if err != nil { + errs = append(errs, err) + continue + } - return artwork, nil - } + return artwork, nil + } - return &Artwork{}, artworks.NewError(t, errors.Join(errs...)) + return &Artwork{}, errors.Join(errs...) + }) } func (a *Artwork) StoreArtwork() *store.Artwork { From f4418f8023a8b941f7425d176d1a3825ca296189 Mon Sep 17 00:00:00 2001 From: XangelMusic Date: Tue, 4 Jun 2024 21:09:11 +0800 Subject: [PATCH 03/30] refactor: error.go created --- artworks/artworks.go | 34 ---------------------------------- artworks/error.go | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 34 deletions(-) create mode 100644 artworks/error.go diff --git a/artworks/artworks.go b/artworks/artworks.go index f60e504..b03218c 100644 --- a/artworks/artworks.go +++ b/artworks/artworks.go @@ -1,8 +1,6 @@ package artworks import ( - "errors" - "fmt" "regexp" "strings" @@ -23,38 +21,6 @@ type Artwork interface { Len() int } -type Error struct { - provider string - cause error -} - -func (e *Error) Error() string { - return fmt.Sprintf("provider %v returned an error: %v", e.provider, e.cause.Error()) -} - -func (e *Error) Unwrap() error { - return e.cause -} - -func NewError(p Provider, find func() (Artwork, error)) (Artwork, error) { - artwork, err := find() - - if err != nil { - return nil, &Error{ - provider: fmt.Sprintf("%T", p), - cause: err, - } - } - - return artwork, nil -} - -// Common errors -var ( - ErrArtworkNotFound = errors.New("artwork not found") - ErrRateLimited = errors.New("provider rate limited") -) - func EscapeMarkdown(content string) string { contents := strings.Split(content, "\n") regex := regexp.MustCompile("^#{1,3}") diff --git a/artworks/error.go b/artworks/error.go new file mode 100644 index 0000000..2a70972 --- /dev/null +++ b/artworks/error.go @@ -0,0 +1,40 @@ +package artworks + +import ( + "errors" + "fmt" +) + +// Common errors +var ( + ErrArtworkNotFound = errors.New("artwork not found") + ErrRateLimited = errors.New("provider rate limited") + AIDisclaimer = "⚠️ Disclaimer" + AIDescription = "This artwork is AI-generated." +) + +type Error struct { + provider string + cause error +} + +func (e *Error) Error() string { + return fmt.Sprintf("provider %v returned an error: %v", e.provider, e.cause.Error()) +} + +func (e *Error) Unwrap() error { + return e.cause +} + +func NewError(p Provider, find func() (Artwork, error)) (Artwork, error) { + artwork, err := find() + + if err != nil { + return nil, &Error{ + provider: fmt.Sprintf("%T", p), + cause: err, + } + } + + return artwork, nil +} From a10572c03bd597245166444e261e573cb6dc6e08 Mon Sep 17 00:00:00 2001 From: XangelMusic Date: Fri, 7 Jun 2024 04:42:19 +0800 Subject: [PATCH 04/30] fix: Twitter regex --- artworks/twitter/twitter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artworks/twitter/twitter.go b/artworks/twitter/twitter.go index f9347d7..b3e8310 100644 --- a/artworks/twitter/twitter.go +++ b/artworks/twitter/twitter.go @@ -52,7 +52,7 @@ type Video struct { } func New() artworks.Provider { - re := regexp.MustCompile(`^(?:mobile\\.)?(?:(?:fix(?:up|v))?x|(?:[fv]x)?twitter)\\.com$`) + re := regexp.MustCompile(`^(?:mobile\.)?(?:(?:fix(?:up|v))?x|(?:[fv]x)?twitter)\.com$`) return &Twitter{ providers: []artworks.Provider{newFxTwitter(re)}, From 024b96a0e5d72d4b5e923c56487ff4eb923b2e60 Mon Sep 17 00:00:00 2001 From: XangelMusic Date: Fri, 7 Jun 2024 06:54:35 +0800 Subject: [PATCH 05/30] refactor: MessageSends functions, new embed.go file and Embed struct --- artworks/artstation/artstation.go | 62 ++++++---------------- artworks/artworks.go | 13 ----- artworks/deviant/deviant.go | 41 ++++++-------- artworks/embed.go | 88 +++++++++++++++++++++++++++++++ artworks/error.go | 2 - artworks/pixiv/pixiv.go | 61 ++++++--------------- artworks/twitter/twitter.go | 75 +++++++------------------- internal/dgoutils/dgoutils.go | 8 +++ 8 files changed, 162 insertions(+), 188 deletions(-) create mode 100644 artworks/embed.go diff --git a/artworks/artstation/artstation.go b/artworks/artstation/artstation.go index 6c4d754..bb2b8e9 100644 --- a/artworks/artstation/artstation.go +++ b/artworks/artstation/artstation.go @@ -126,13 +126,8 @@ func (artwork *ArtstationResponse) StoreArtwork() *store.Artwork { } func (artwork *ArtstationResponse) MessageSends(footer string, tagsEnabled bool) ([]*discordgo.MessageSend, error) { - var ( - length = len(artwork.Assets) - pages = make([]*discordgo.MessageSend, 0, length) - eb = embeds.NewBuilder() - ) - - if length == 0 { + if len(artwork.Assets) == 0 { + eb := embeds.NewBuilder() eb.Title("❎ An error has occured.") eb.Description("Artwork has been deleted or the ID does not exist.") eb.Footer(footer, "") @@ -142,51 +137,28 @@ func (artwork *ArtstationResponse) MessageSends(footer string, tagsEnabled bool) }, nil } - if length > 1 { - eb.Title(fmt.Sprintf("%v by %v | Page %v / %v", artwork.Title, artwork.User.Name, 1, length)) - } else { - eb.Title(fmt.Sprintf("%v by %v", artwork.Title, artwork.User.Name)) + eb := &artworks.Embed{ + Title: artwork.Title, + Username: artwork.User.Name, + FieldName1: "Likes", + FieldValue1: strconv.Itoa(artwork.LikesCount), + FieldName2: "Views", + FieldValue2: []string{strconv.Itoa(artwork.ViewsCount)}, + URL: artwork.Permalink, + Timestamp: artwork.CreatedAt, + Footer: footer, + AIGenerated: artwork.AIGenerated, } if tagsEnabled { - desc := bluemonday.StrictPolicy().Sanitize(artwork.Description) - eb.Description(artworks.EscapeMarkdown(desc)) - } - - eb.URL(artwork.URL()). - AddField("Likes", strconv.Itoa(artwork.LikesCount), true). - AddField("Views", strconv.Itoa(artwork.ViewsCount), true). - Timestamp(artwork.CreatedAt) - - if footer != "" { - eb.Footer(footer, "") + eb.Description = bluemonday.StrictPolicy().Sanitize(artwork.Description) } - if artwork.AIGenerated { - eb.AddField("⚠️ Disclaimer", "This artwork is AI-generated.") - } - - eb.Image(artwork.Assets[0].ImageURL) - pages = append(pages, &discordgo.MessageSend{Embeds: []*discordgo.MessageEmbed{eb.Finalize()}}) - if length > 1 { - for ind, image := range artwork.Assets[1:] { - eb := embeds.NewBuilder() - - eb.Title(fmt.Sprintf("%v by %v | Page %v / %v", artwork.Title, artwork.User.Name, ind+2, length)). - Image(image.ImageURL). - URL(artwork.URL()). - Timestamp(artwork.CreatedAt) - - if footer != "" { - eb.Footer(footer, "") - } - - eb.AddField("Likes", strconv.Itoa(artwork.LikesCount), true) - pages = append(pages, &discordgo.MessageSend{Embeds: []*discordgo.MessageEmbed{eb.Finalize()}}) - } + for _, image := range artwork.Assets { + eb.Images = append(eb.Images, image.ImageURL) } - return pages, nil + return eb.ToEmbed(), nil } func (artwork *ArtstationResponse) URL() string { diff --git a/artworks/artworks.go b/artworks/artworks.go index b03218c..66e92c3 100644 --- a/artworks/artworks.go +++ b/artworks/artworks.go @@ -1,7 +1,6 @@ package artworks import ( - "regexp" "strings" "github.com/VTGare/boe-tea-go/store" @@ -21,18 +20,6 @@ type Artwork interface { Len() int } -func EscapeMarkdown(content string) string { - contents := strings.Split(content, "\n") - regex := regexp.MustCompile("^#{1,3}") - - for i, line := range contents { - if regex.MatchString(line) { - contents[i] = "\\" + line - } - } - return strings.Join(contents, "\n") -} - func IsAIGenerated(contents ...string) bool { aiTags := []string{ "aiart", diff --git a/artworks/deviant/deviant.go b/artworks/deviant/deviant.go index 329b91f..d3e0d48 100644 --- a/artworks/deviant/deviant.go +++ b/artworks/deviant/deviant.go @@ -14,7 +14,6 @@ import ( "github.com/VTGare/boe-tea-go/internal/arrays" "github.com/VTGare/boe-tea-go/messages" "github.com/VTGare/boe-tea-go/store" - "github.com/VTGare/embeds" "github.com/bwmarrin/discordgo" ) @@ -120,36 +119,28 @@ func (d *DeviantArt) Enabled(g *store.Guild) bool { } func (a *Artwork) MessageSends(footer string, tagsEnabled bool) ([]*discordgo.MessageSend, error) { - eb := embeds.NewBuilder() - - eb.Title(fmt.Sprintf("%v by %v", a.Title, a.Author.Name)). - Image(a.ImageURL). - URL(a.url). - Timestamp(a.CreatedAt). - AddField("Views", strconv.Itoa(a.Views), true). - AddField("Favorites", strconv.Itoa(a.Favorites), true) + eb := &artworks.Embed{ + Title: a.Title, + Username: a.Author.Name, + FieldName1: "Views", + FieldValue1: strconv.Itoa(a.Views), + FieldName2: "Favorites", + FieldValue2: []string{strconv.Itoa(a.Favorites)}, + Images: []string{a.ImageURL}, + URL: a.url, + Timestamp: a.CreatedAt, + Footer: footer, + AIGenerated: a.AIGenerated, + } if tagsEnabled && len(a.Tags) > 0 { tags := arrays.Map(a.Tags, func(s string) string { - return messages.NamedLink( - s, "https://www.deviantart.com/tag/"+s, - ) + return messages.NamedLink(s, "https://www.deviantart.com/tag/"+s) }) - - eb.Description("**Tags:**\n" + strings.Join(tags, " • ")) - } - - if footer != "" { - eb.Footer(footer, "") - } - - if a.AIGenerated { - eb.AddField("⚠️ Disclaimer", "This artwork is AI-generated.") + eb.Description = fmt.Sprintf("**Tags:**\n%v", strings.Join(tags, " • ")) } - return []*discordgo.MessageSend{ - {Embeds: []*discordgo.MessageEmbed{eb.Finalize()}}, - }, nil + return eb.ToEmbed(), nil } func (a *Artwork) StoreArtwork() *store.Artwork { diff --git a/artworks/embed.go b/artworks/embed.go new file mode 100644 index 0000000..65e3a38 --- /dev/null +++ b/artworks/embed.go @@ -0,0 +1,88 @@ +package artworks + +import ( + "fmt" + "strings" + "time" + + "github.com/VTGare/boe-tea-go/internal/dgoutils" + "github.com/VTGare/embeds" + "github.com/bwmarrin/discordgo" +) + +type Embed struct { + Title string + Username string + Description string + FieldName1 string + FieldValue1 string + FieldName2 string + FieldValue2 []string + Images []string + Files []*discordgo.File + URL string + Timestamp time.Time + Footer string + AIGenerated bool +} + +func (e *Embed) ToEmbed() []*discordgo.MessageSend { + var ( + length = dgoutils.Ternary(len(e.Files) > 0, 1, len(e.Images)) + pages = make([]*discordgo.MessageSend, 0, length) + ) + + for i := 0; i < length; i++ { + eb := embeds.NewBuilder() + + eb.Title(EscapeMarkdown( + dgoutils.Ternary(length == 1, + fmt.Sprintf("%v by %v", e.Title, e.Username), + fmt.Sprintf("%v by %v | Page %v / %v", e.Title, e.Username, i+1, length), + ), + )) + + if len(e.Images) != 0 { + eb.Image(e.Images[i]) + } + + eb.URL(e.URL) + eb.Timestamp(e.Timestamp) + + if i < len(e.FieldValue2) { + eb.AddField(e.FieldName1, e.FieldValue1, true) + eb.AddField(e.FieldName2, e.FieldValue2[i], true) + } + + if i == 0 { + if e.Description != "" { + eb.Description(EscapeMarkdown(e.Description)) + } + + if e.AIGenerated { + eb.AddField("⚠️ Disclaimer", "This artwork is AI-generated.") + } + } + + if e.Footer != "" { + eb.Footer(e.Footer, "") + } + + pages = append(pages, &discordgo.MessageSend{ + Embeds: []*discordgo.MessageEmbed{eb.Finalize()}, + Files: e.Files, + }) + } + + return pages +} + +func EscapeMarkdown(content string) string { + markdown := []string{"-", "_", "#", "*", "`", ">"} + + for _, m := range markdown { + content = strings.ReplaceAll(content, m, "\\"+m) + } + + return content +} diff --git a/artworks/error.go b/artworks/error.go index 2a70972..0bd559d 100644 --- a/artworks/error.go +++ b/artworks/error.go @@ -9,8 +9,6 @@ import ( var ( ErrArtworkNotFound = errors.New("artwork not found") ErrRateLimited = errors.New("provider rate limited") - AIDisclaimer = "⚠️ Disclaimer" - AIDescription = "This artwork is AI-generated." ) type Error struct { diff --git a/artworks/pixiv/pixiv.go b/artworks/pixiv/pixiv.go index 80594d8..a712579 100644 --- a/artworks/pixiv/pixiv.go +++ b/artworks/pixiv/pixiv.go @@ -11,7 +11,6 @@ import ( "github.com/VTGare/boe-tea-go/internal/arrays" "github.com/VTGare/boe-tea-go/messages" "github.com/VTGare/boe-tea-go/store" - "github.com/VTGare/embeds" "github.com/bwmarrin/discordgo" "github.com/everpcpc/pixiv" ) @@ -177,61 +176,31 @@ func (a *Artwork) StoreArtwork() *store.Artwork { } func (a *Artwork) MessageSends(footer string, tagsEnabled bool) ([]*discordgo.MessageSend, error) { - var ( - length = len(a.Images) - pages = make([]*discordgo.MessageSend, 0, length) - eb = embeds.NewBuilder() - ) - - if length > 1 { - eb.Title(fmt.Sprintf("%v by %v | Page %v / %v", a.Title, a.Author, 1, length)) - } else { - eb.Title(fmt.Sprintf("%v by %v", a.Title, a.Author)) + eb := &artworks.Embed{ + Title: a.Title, + Username: a.Author, + FieldName1: "Likes", + FieldValue1: strconv.Itoa(a.Likes), + FieldName2: "Original quality", + URL: a.url, + Timestamp: time.Time{}, + Footer: footer, + AIGenerated: a.AIGenerated, } if tagsEnabled && len(a.Tags) > 0 { tags := arrays.Map(a.Tags, func(s string) string { return fmt.Sprintf("[%v](https://pixiv.net/en/tags/%v/artworks)", s, s) }) - - eb.Description(fmt.Sprintf("**Tags**\n%v", strings.Join(tags, " • "))) - } - - eb.URL(a.url). - AddField("Likes", strconv.Itoa(a.Likes), true). - AddField("Original quality", messages.ClickHere(a.Images[0].originalProxy(a.proxy)), true). - Timestamp(a.CreatedAt) - - if footer != "" { - eb.Footer(footer, "") - } - - if a.AIGenerated { - eb.AddField("⚠️ Disclaimer", "This artwork is AI-generated.") + eb.Description = fmt.Sprintf("**Tags**\n%v", strings.Join(tags, " • ")) } - eb.Image(a.Images[0].previewProxy(a.proxy)) - pages = append(pages, &discordgo.MessageSend{Embeds: []*discordgo.MessageEmbed{eb.Finalize()}}) - if length > 1 { - for ind, image := range a.Images[1:] { - eb := embeds.NewBuilder() - - eb.Title(fmt.Sprintf("%v by %v | Page %v / %v", a.Title, a.Author, ind+2, length)) - eb.Image(image.previewProxy(a.proxy)) - eb.URL(a.url).Timestamp(a.CreatedAt) - - if footer != "" { - eb.Footer(footer, "") - } - - eb.AddField("Likes", strconv.Itoa(a.Likes), true) - eb.AddField("Original quality", messages.ClickHere(image.originalProxy(a.proxy)), true) - - pages = append(pages, &discordgo.MessageSend{Embeds: []*discordgo.MessageEmbed{eb.Finalize()}}) - } + for _, image := range a.Images { + eb.Images = append(eb.Images, image.previewProxy(a.proxy)) + eb.FieldValue2 = append(eb.FieldValue2, messages.ClickHere(image.originalProxy(a.proxy))) } - return pages, nil + return eb.ToEmbed(), nil } func (a *Artwork) URL() string { diff --git a/artworks/twitter/twitter.go b/artworks/twitter/twitter.go index b3e8310..9f991f2 100644 --- a/artworks/twitter/twitter.go +++ b/artworks/twitter/twitter.go @@ -105,8 +105,8 @@ func (a *Artwork) StoreArtwork() *store.Artwork { // MessageSends transforms an artwork to discordgo embeds. func (a *Artwork) MessageSends(footer string, _ bool) ([]*discordgo.MessageSend, error) { - eb := embeds.NewBuilder() if a.FullName == "" && a.Len() == 0 { + eb := embeds.NewBuilder() eb.Title("❎ Tweet doesn't exist.") eb.Description("The tweet is NSFW or doesn't exist.\n\nUnsafe tweets can't be embedded due to API changes.") eb.Footer(footer, "") @@ -116,80 +116,41 @@ func (a *Artwork) MessageSends(footer string, _ bool) ([]*discordgo.MessageSend, }, nil } - eb.URL(a.Permalink).Description(artworks.EscapeMarkdown(a.Content)).Timestamp(a.Timestamp) - - if a.Retweets > 0 { - eb.AddField("Retweets", strconv.Itoa(a.Retweets), true) - } - - if a.Likes > 0 { - eb.AddField("Likes", strconv.Itoa(a.Likes), true) - } - - if footer != "" { - eb.Footer(footer, "") - } - - if a.AIGenerated { - eb.AddField("⚠️ Disclaimer", "This artwork is AI-generated.") + eb := &artworks.Embed{ + Title: a.FullName, + Username: a.Username, + Description: a.Content, + FieldName1: "Likes", + FieldValue1: strconv.Itoa(a.Likes), + FieldName2: "Retweets", + FieldValue2: []string{strconv.Itoa(a.Retweets)}, + URL: a.Permalink, + Timestamp: a.Timestamp, + AIGenerated: a.AIGenerated, } if len(a.Videos) > 0 { return a.videoEmbed(eb) } - length := len(a.Photos) - tweets := make([]*discordgo.MessageSend, 0, length) - if length > 1 { - eb.Title(fmt.Sprintf("%v (%v) | Page %v / %v", a.FullName, a.Username, 1, length)) - } else { - eb.Title(fmt.Sprintf("%v (%v)", a.FullName, a.Username)) + for _, image := range a.Photos { + eb.Images = append(eb.Images, image) } - if length > 0 { - eb.Image(a.Photos[0]) - } - - tweets = append(tweets, &discordgo.MessageSend{ - Embeds: []*discordgo.MessageEmbed{eb.Finalize()}, - }) - - if len(a.Photos) > 1 { - for ind, photo := range a.Photos[1:] { - eb := embeds.NewBuilder() - - eb.Title(fmt.Sprintf("%v (%v) | Page %v / %v", a.FullName, a.Username, ind+2, length)).URL(a.Permalink) - eb.Image(photo).Timestamp(a.Timestamp) - - if footer != "" { - eb.Footer(footer, "") - } - - tweets = append(tweets, &discordgo.MessageSend{Embeds: []*discordgo.MessageEmbed{eb.Finalize()}}) - } - } - - return tweets, nil + return eb.ToEmbed(), nil } -func (a *Artwork) videoEmbed(eb *embeds.Builder) ([]*discordgo.MessageSend, error) { - files := make([]*discordgo.File, 0, len(a.Videos)) +func (a *Artwork) videoEmbed(eb *artworks.Embed) ([]*discordgo.MessageSend, error) { for _, video := range a.Videos { file, err := downloadVideo(video.URL) if err != nil { return nil, err } - files = append(files, file) - } - - eb.Title(fmt.Sprintf("%v (%v)", a.FullName, a.Username)) - msg := &discordgo.MessageSend{ - Embeds: []*discordgo.MessageEmbed{eb.Finalize()}, - Files: files, + eb.Files = append(eb.Files, file) } - return []*discordgo.MessageSend{msg}, nil + return eb.ToEmbed(), nil } func downloadVideo(fileURL string) (*discordgo.File, error) { diff --git a/internal/dgoutils/dgoutils.go b/internal/dgoutils/dgoutils.go index 4f86d5e..5e40ac8 100644 --- a/internal/dgoutils/dgoutils.go +++ b/internal/dgoutils/dgoutils.go @@ -19,6 +19,14 @@ var ( ErrRangeSyntax = errors.New("range low is higher than range high") ) +func Ternary[T any](condition bool, a T, b T) T { + if condition { + return a + } + + return b +} + func ValidateArgs(gctx *gumi.Ctx, argsLen int) error { if gctx.Args.Len() < argsLen { return messages.ErrIncorrectCmd(gctx.Command) From d6688d192c50352a5ef934a3ae569460113c849f Mon Sep 17 00:00:00 2001 From: XangelMusic Date: Fri, 7 Jun 2024 09:03:29 +0800 Subject: [PATCH 06/30] fix: Embed package --- artworks/artstation/artstation.go | 3 ++- artworks/deviant/deviant.go | 3 ++- artworks/{ => embed}/embed.go | 2 +- artworks/pixiv/pixiv.go | 3 ++- artworks/twitter/twitter.go | 5 +++-- 5 files changed, 10 insertions(+), 6 deletions(-) rename artworks/{ => embed}/embed.go (99%) diff --git a/artworks/artstation/artstation.go b/artworks/artstation/artstation.go index bb2b8e9..d48ae39 100644 --- a/artworks/artstation/artstation.go +++ b/artworks/artstation/artstation.go @@ -3,6 +3,7 @@ package artstation import ( "encoding/json" "fmt" + "github.com/VTGare/boe-tea-go/artworks/embed" "net/http" "regexp" "strconv" @@ -137,7 +138,7 @@ func (artwork *ArtstationResponse) MessageSends(footer string, tagsEnabled bool) }, nil } - eb := &artworks.Embed{ + eb := &embed.Embed{ Title: artwork.Title, Username: artwork.User.Name, FieldName1: "Likes", diff --git a/artworks/deviant/deviant.go b/artworks/deviant/deviant.go index d3e0d48..9f9ecb5 100644 --- a/artworks/deviant/deviant.go +++ b/artworks/deviant/deviant.go @@ -3,6 +3,7 @@ package deviant import ( "encoding/json" "fmt" + "github.com/VTGare/boe-tea-go/artworks/embed" "net/http" "net/url" "regexp" @@ -119,7 +120,7 @@ func (d *DeviantArt) Enabled(g *store.Guild) bool { } func (a *Artwork) MessageSends(footer string, tagsEnabled bool) ([]*discordgo.MessageSend, error) { - eb := &artworks.Embed{ + eb := &embed.Embed{ Title: a.Title, Username: a.Author.Name, FieldName1: "Views", diff --git a/artworks/embed.go b/artworks/embed/embed.go similarity index 99% rename from artworks/embed.go rename to artworks/embed/embed.go index 65e3a38..fc0b996 100644 --- a/artworks/embed.go +++ b/artworks/embed/embed.go @@ -1,4 +1,4 @@ -package artworks +package embed import ( "fmt" diff --git a/artworks/pixiv/pixiv.go b/artworks/pixiv/pixiv.go index a712579..3657380 100644 --- a/artworks/pixiv/pixiv.go +++ b/artworks/pixiv/pixiv.go @@ -2,6 +2,7 @@ package pixiv import ( "fmt" + "github.com/VTGare/boe-tea-go/artworks/embed" "regexp" "strconv" "strings" @@ -176,7 +177,7 @@ func (a *Artwork) StoreArtwork() *store.Artwork { } func (a *Artwork) MessageSends(footer string, tagsEnabled bool) ([]*discordgo.MessageSend, error) { - eb := &artworks.Embed{ + eb := &embed.Embed{ Title: a.Title, Username: a.Author, FieldName1: "Likes", diff --git a/artworks/twitter/twitter.go b/artworks/twitter/twitter.go index 9f991f2..8a55bda 100644 --- a/artworks/twitter/twitter.go +++ b/artworks/twitter/twitter.go @@ -4,6 +4,7 @@ import ( "bytes" "errors" "fmt" + "github.com/VTGare/boe-tea-go/artworks/embed" "io" "net/http" "net/url" @@ -116,7 +117,7 @@ func (a *Artwork) MessageSends(footer string, _ bool) ([]*discordgo.MessageSend, }, nil } - eb := &artworks.Embed{ + eb := &embed.Embed{ Title: a.FullName, Username: a.Username, Description: a.Content, @@ -140,7 +141,7 @@ func (a *Artwork) MessageSends(footer string, _ bool) ([]*discordgo.MessageSend, return eb.ToEmbed(), nil } -func (a *Artwork) videoEmbed(eb *artworks.Embed) ([]*discordgo.MessageSend, error) { +func (a *Artwork) videoEmbed(eb *embed.Embed) ([]*discordgo.MessageSend, error) { for _, video := range a.Videos { file, err := downloadVideo(video.URL) if err != nil { From 55bc7b22c564b277d69d87db0741e9c03b92a278 Mon Sep 17 00:00:00 2001 From: XangelMusic Date: Fri, 7 Jun 2024 09:03:29 +0800 Subject: [PATCH 07/30] fix: Embed package --- artworks/artstation/artstation.go | 5 +++-- artworks/deviant/deviant.go | 6 +++--- artworks/{ => embed}/embed.go | 21 +++++++++++++-------- artworks/pixiv/pixiv.go | 5 +++-- artworks/twitter/twitter.go | 5 +++-- 5 files changed, 25 insertions(+), 17 deletions(-) rename artworks/{ => embed}/embed.go (89%) diff --git a/artworks/artstation/artstation.go b/artworks/artstation/artstation.go index bb2b8e9..dac53fa 100644 --- a/artworks/artstation/artstation.go +++ b/artworks/artstation/artstation.go @@ -3,6 +3,7 @@ package artstation import ( "encoding/json" "fmt" + "github.com/VTGare/boe-tea-go/artworks/embed" "net/http" "regexp" "strconv" @@ -137,7 +138,7 @@ func (artwork *ArtstationResponse) MessageSends(footer string, tagsEnabled bool) }, nil } - eb := &artworks.Embed{ + eb := &embed.Embed{ Title: artwork.Title, Username: artwork.User.Name, FieldName1: "Likes", @@ -151,7 +152,7 @@ func (artwork *ArtstationResponse) MessageSends(footer string, tagsEnabled bool) } if tagsEnabled { - eb.Description = bluemonday.StrictPolicy().Sanitize(artwork.Description) + eb.Tags = bluemonday.StrictPolicy().Sanitize(artwork.Description) } for _, image := range artwork.Assets { diff --git a/artworks/deviant/deviant.go b/artworks/deviant/deviant.go index d3e0d48..4b82bb0 100644 --- a/artworks/deviant/deviant.go +++ b/artworks/deviant/deviant.go @@ -2,7 +2,7 @@ package deviant import ( "encoding/json" - "fmt" + "github.com/VTGare/boe-tea-go/artworks/embed" "net/http" "net/url" "regexp" @@ -119,7 +119,7 @@ func (d *DeviantArt) Enabled(g *store.Guild) bool { } func (a *Artwork) MessageSends(footer string, tagsEnabled bool) ([]*discordgo.MessageSend, error) { - eb := &artworks.Embed{ + eb := &embed.Embed{ Title: a.Title, Username: a.Author.Name, FieldName1: "Views", @@ -137,7 +137,7 @@ func (a *Artwork) MessageSends(footer string, tagsEnabled bool) ([]*discordgo.Me tags := arrays.Map(a.Tags, func(s string) string { return messages.NamedLink(s, "https://www.deviantart.com/tag/"+s) }) - eb.Description = fmt.Sprintf("**Tags:**\n%v", strings.Join(tags, " • ")) + eb.Tags = strings.Join(tags, " • ") } return eb.ToEmbed(), nil diff --git a/artworks/embed.go b/artworks/embed/embed.go similarity index 89% rename from artworks/embed.go rename to artworks/embed/embed.go index 65e3a38..e3cb8f5 100644 --- a/artworks/embed.go +++ b/artworks/embed/embed.go @@ -1,4 +1,4 @@ -package artworks +package embed import ( "fmt" @@ -14,6 +14,7 @@ type Embed struct { Title string Username string Description string + Tags string FieldName1 string FieldValue1 string FieldName2 string @@ -49,21 +50,25 @@ func (e *Embed) ToEmbed() []*discordgo.MessageSend { eb.URL(e.URL) eb.Timestamp(e.Timestamp) - if i < len(e.FieldValue2) { - eb.AddField(e.FieldName1, e.FieldValue1, true) - eb.AddField(e.FieldName2, e.FieldValue2[i], true) - } - if i == 0 { if e.Description != "" { eb.Description(EscapeMarkdown(e.Description)) } - if e.AIGenerated { - eb.AddField("⚠️ Disclaimer", "This artwork is AI-generated.") + if e.Tags != "" { + eb.AddField("Tags", e.Tags) } } + if i < len(e.FieldValue2) { + eb.AddField(e.FieldName1, e.FieldValue1, true) + eb.AddField(e.FieldName2, e.FieldValue2[i], true) + } + + if i == 0 && e.AIGenerated { + eb.AddField("⚠️ Disclaimer", "This artwork is AI-generated.") + } + if e.Footer != "" { eb.Footer(e.Footer, "") } diff --git a/artworks/pixiv/pixiv.go b/artworks/pixiv/pixiv.go index a712579..3e39b25 100644 --- a/artworks/pixiv/pixiv.go +++ b/artworks/pixiv/pixiv.go @@ -2,6 +2,7 @@ package pixiv import ( "fmt" + "github.com/VTGare/boe-tea-go/artworks/embed" "regexp" "strconv" "strings" @@ -176,7 +177,7 @@ func (a *Artwork) StoreArtwork() *store.Artwork { } func (a *Artwork) MessageSends(footer string, tagsEnabled bool) ([]*discordgo.MessageSend, error) { - eb := &artworks.Embed{ + eb := &embed.Embed{ Title: a.Title, Username: a.Author, FieldName1: "Likes", @@ -192,7 +193,7 @@ func (a *Artwork) MessageSends(footer string, tagsEnabled bool) ([]*discordgo.Me tags := arrays.Map(a.Tags, func(s string) string { return fmt.Sprintf("[%v](https://pixiv.net/en/tags/%v/artworks)", s, s) }) - eb.Description = fmt.Sprintf("**Tags**\n%v", strings.Join(tags, " • ")) + eb.Tags = strings.Join(tags, " • ") } for _, image := range a.Images { diff --git a/artworks/twitter/twitter.go b/artworks/twitter/twitter.go index 9f991f2..8a55bda 100644 --- a/artworks/twitter/twitter.go +++ b/artworks/twitter/twitter.go @@ -4,6 +4,7 @@ import ( "bytes" "errors" "fmt" + "github.com/VTGare/boe-tea-go/artworks/embed" "io" "net/http" "net/url" @@ -116,7 +117,7 @@ func (a *Artwork) MessageSends(footer string, _ bool) ([]*discordgo.MessageSend, }, nil } - eb := &artworks.Embed{ + eb := &embed.Embed{ Title: a.FullName, Username: a.Username, Description: a.Content, @@ -140,7 +141,7 @@ func (a *Artwork) MessageSends(footer string, _ bool) ([]*discordgo.MessageSend, return eb.ToEmbed(), nil } -func (a *Artwork) videoEmbed(eb *artworks.Embed) ([]*discordgo.MessageSend, error) { +func (a *Artwork) videoEmbed(eb *embed.Embed) ([]*discordgo.MessageSend, error) { for _, video := range a.Videos { file, err := downloadVideo(video.URL) if err != nil { From 69f8a6dcb4287963d4caf9a025f8710444eb1bc2 Mon Sep 17 00:00:00 2001 From: XangelMusic Date: Fri, 7 Jun 2024 21:44:47 +0800 Subject: [PATCH 08/30] fix: Adjusted Pixiv for testing --- artworks/artstation/artstation_suite_test.go | 4 ++-- artworks/pixiv/pixiv.go | 9 ++++++--- artworks/pixiv/pixiv_suite_test.go | 2 +- cmd/boetea/main.go | 4 ++-- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/artworks/artstation/artstation_suite_test.go b/artworks/artstation/artstation_suite_test.go index 7e3d46c..62006cb 100644 --- a/artworks/artstation/artstation_suite_test.go +++ b/artworks/artstation/artstation_suite_test.go @@ -16,9 +16,9 @@ func TestArtstation(t *testing.T) { var _ = DescribeTable( "Match Artstation URL", func(url string, expectedID string, expectedResult bool) { - as := artstation.New() + provider := artstation.New() - id, ok := as.Match(url) + id, ok := provider.Match(url) Expect(id).To(BeEquivalentTo(expectedID)) Expect(ok).To(BeEquivalentTo(expectedResult)) }, diff --git a/artworks/pixiv/pixiv.go b/artworks/pixiv/pixiv.go index 3e39b25..7865ec9 100644 --- a/artworks/pixiv/pixiv.go +++ b/artworks/pixiv/pixiv.go @@ -44,12 +44,15 @@ type Image struct { Original string } -func New(proxyHost, authToken, refreshToken string) (artworks.Provider, error) { +func LoadAuth(authToken, refreshToken string) error { _, err := pixiv.LoadAuth(authToken, refreshToken, time.Now()) if err != nil { - return nil, err + return err } + return nil +} +func New(proxyHost string) artworks.Provider { if proxyHost == "" { proxyHost = "https://boetea.dev" } @@ -58,7 +61,7 @@ func New(proxyHost, authToken, refreshToken string) (artworks.Provider, error) { app: pixiv.NewApp(), proxyHost: proxyHost, regex: regexp.MustCompile(`(?i)https?://(?:www\.)?pixiv\.net/(?:en/)?(?:artworks/|member_illust\.php\?)(?:mode=medium&)?(?:illust_id=)?([0-9]+)`), - }, nil + } } func (p *Pixiv) Match(s string) (string, bool) { diff --git a/artworks/pixiv/pixiv_suite_test.go b/artworks/pixiv/pixiv_suite_test.go index f83c033..9c13139 100644 --- a/artworks/pixiv/pixiv_suite_test.go +++ b/artworks/pixiv/pixiv_suite_test.go @@ -16,7 +16,7 @@ func TestPixiv(t *testing.T) { var _ = DescribeTable( "Match Pixiv URL", func(url string, expectedID string, expectedResult bool) { - provider := pixiv.Pixiv{} + provider := pixiv.New("") id, ok := provider.Match(url) Expect(id).To(BeEquivalentTo(expectedID)) diff --git a/cmd/boetea/main.go b/cmd/boetea/main.go index 587f3d0..5fc31e5 100644 --- a/cmd/boetea/main.go +++ b/cmd/boetea/main.go @@ -99,9 +99,9 @@ func main() { b.AddProvider(twitter.New()) b.AddProvider(deviant.New()) - if pixiv, err := pixiv.New(cfg.Pixiv.ProxyHost, cfg.Pixiv.AuthToken, cfg.Pixiv.RefreshToken); err == nil { + if err := pixiv.LoadAuth(cfg.Pixiv.AuthToken, cfg.Pixiv.RefreshToken); err == nil { log.Info("Successfully logged into Pixiv.") - b.AddProvider(pixiv) + b.AddProvider(pixiv.New(cfg.Pixiv.ProxyHost)) } b.AddRouter(&gumi.Router{ From 08fb2cbede14c86b32310dde15bad286870af56b Mon Sep 17 00:00:00 2001 From: XangelMusic <22012301+XangelMusic@users.noreply.github.com> Date: Sat, 8 Jun 2024 16:22:30 +0800 Subject: [PATCH 09/30] Update pixiv.go --- artworks/pixiv/pixiv.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artworks/pixiv/pixiv.go b/artworks/pixiv/pixiv.go index 7865ec9..bc5c680 100644 --- a/artworks/pixiv/pixiv.go +++ b/artworks/pixiv/pixiv.go @@ -187,7 +187,7 @@ func (a *Artwork) MessageSends(footer string, tagsEnabled bool) ([]*discordgo.Me FieldValue1: strconv.Itoa(a.Likes), FieldName2: "Original quality", URL: a.url, - Timestamp: time.Time{}, + Timestamp: a.CreatedAt, Footer: footer, AIGenerated: a.AIGenerated, } From dfc6879dddc1b397aef5a3f591f6644971af7a99 Mon Sep 17 00:00:00 2001 From: XangelMusic Date: Wed, 12 Jun 2024 01:46:36 +0800 Subject: [PATCH 10/30] boost: Internal utility functions --- artworks/artworks.go | 10 ++---- artworks/deviant/deviant.go | 2 +- artworks/pixiv/pixiv.go | 56 +++++++++++++-------------------- commands/general.go | 5 ++- commands/memes.go | 10 +++--- commands/settings.go | 14 ++++----- commands/user.go | 6 ++-- handlers/handlers.go | 2 +- internal/arrays/arrays.go | 58 +++++++++++++++++++++++++++++++++-- internal/dgoutils/dgoutils.go | 10 +++++- post/post.go | 6 ++-- store/users.go | 2 +- 12 files changed, 109 insertions(+), 72 deletions(-) diff --git a/artworks/artworks.go b/artworks/artworks.go index 1c8c122..3761c25 100644 --- a/artworks/artworks.go +++ b/artworks/artworks.go @@ -1,6 +1,7 @@ package artworks import ( + "github.com/VTGare/boe-tea-go/internal/arrays" "strings" "github.com/VTGare/boe-tea-go/store" @@ -32,12 +33,5 @@ func IsAIGenerated(content ...string) bool { "stablediffusion", } - for _, tag := range content { - for _, test := range aiTags { - if strings.EqualFold(tag, test) { - return true - } - } - } - return false + return arrays.CheckArraysFunc(strings.EqualFold, content, aiTags) } diff --git a/artworks/deviant/deviant.go b/artworks/deviant/deviant.go index fdf9680..9d7c37d 100644 --- a/artworks/deviant/deviant.go +++ b/artworks/deviant/deviant.go @@ -64,7 +64,7 @@ type deviantEmbed struct { func New() artworks.Provider { return &DeviantArt{ - regex: regexp.MustCompile(`(?i)https://(?:www\.)?deviantart\.com/[\w]+/art/([\w\-]+)`), + regex: regexp.MustCompile(`(?i)https://(?:www\.)?deviantart\.com/\w+/art/([\w\-]+)`), } } diff --git a/artworks/pixiv/pixiv.go b/artworks/pixiv/pixiv.go index bc5c680..5f27c83 100644 --- a/artworks/pixiv/pixiv.go +++ b/artworks/pixiv/pixiv.go @@ -2,14 +2,15 @@ package pixiv import ( "fmt" - "github.com/VTGare/boe-tea-go/artworks/embed" "regexp" "strconv" "strings" "time" "github.com/VTGare/boe-tea-go/artworks" + "github.com/VTGare/boe-tea-go/artworks/embed" "github.com/VTGare/boe-tea-go/internal/arrays" + "github.com/VTGare/boe-tea-go/internal/dgoutils" "github.com/VTGare/boe-tea-go/messages" "github.com/VTGare/boe-tea-go/store" "github.com/bwmarrin/discordgo" @@ -89,13 +90,6 @@ func (p *Pixiv) Find(id string) (artworks.Artwork, error) { return nil, artworks.ErrArtworkNotFound } - author := "" - if illust.User != nil { - author = illust.User.Name - } else { - author = "Unknown" - } - tags := make([]string, 0) nsfw := false for _, tag := range illust.Tags { @@ -103,11 +97,10 @@ func (p *Pixiv) Find(id string) (artworks.Artwork, error) { nsfw = true } - if tag.TranslatedName != "" { - tags = append(tags, tag.TranslatedName) - } else { - tags = append(tags, tag.Name) - } + tags = dgoutils.Ternary(tag.TranslatedName != "", + append(tags, tag.TranslatedName), + append(tags, tag.Name), + ) } images := make([]*Image, 0, illust.PageCount) @@ -131,38 +124,33 @@ func (p *Pixiv) Find(id string) (artworks.Artwork, error) { images = append(images, img) } - artwork := &Artwork{ - ID: id, - url: "https://www.pixiv.net/en/artworks/" + id, - Title: illust.Title, - Author: author, - Tags: tags, - Images: images, - NSFW: nsfw, - Type: illust.Type, - Pages: illust.PageCount, - Likes: illust.TotalBookmarks, - CreatedAt: illust.CreateDate, - - proxy: p.proxyHost, - } - errImages := []string{ "limit_sanity_level_360.png", "limit_unknown_360.png", } for _, img := range errImages { - if artwork.Images[0].Original == fmt.Sprintf("https://s.pximg.net/common/images/%s", img) { + if images[0].Original == fmt.Sprintf("https://s.pximg.net/common/images/%s", img) { return nil, artworks.ErrRateLimited } } - if illust.IllustAIType == pixiv.IllustAITypeAIGenerated { - artwork.AIGenerated = true - } + return &Artwork{ + ID: id, + url: "https://www.pixiv.net/en/artworks/" + id, + Title: illust.Title, + Author: dgoutils.Ternary(illust.User != nil, illust.User.Name, "Unknown"), + Tags: tags, + Images: images, + NSFW: nsfw, + Type: illust.Type, + Pages: illust.PageCount, + Likes: illust.TotalBookmarks, + CreatedAt: illust.CreateDate, + AIGenerated: illust.IllustAIType == pixiv.IllustAITypeAIGenerated, - return artwork, nil + proxy: p.proxyHost, + }, nil }) } diff --git a/commands/general.go b/commands/general.go index 6265204..60d0ed7 100644 --- a/commands/general.go +++ b/commands/general.go @@ -243,9 +243,8 @@ func feedback(*bot.Bot) func(*gumi.Ctx) error { if len(gctx.Event.Attachments) > 0 { att := gctx.Event.Attachments[0] - if strings.HasSuffix(att.Filename, "png") || - strings.HasSuffix(att.Filename, "jpg") || - strings.HasSuffix(att.Filename, "gif") { + if arrays.CheckFuncCompareArgs( + strings.HasSuffix, att.Filename, "png", "jpg", "gif") { eb.Image(att.URL) } } diff --git a/commands/memes.go b/commands/memes.go index a080a83..be3dfe9 100644 --- a/commands/memes.go +++ b/commands/memes.go @@ -173,12 +173,10 @@ func gamba(*bot.Bot) func(*gumi.Ctx) error { return func(gctx *gumi.Ctx) error { getItTwisted := rand.Intn(10) != 0 - var text string - if getItTwisted { - text = `🦍 🗣 GET IT TWISTED 🌪 , GAMBLE ✅ . PLEASE START GAMBLING 👍 . GAMBLING IS AN INVESTMENT 🎰 AND AN INVESTMENT ONLY 👍 . YOU WILL PROFIT 💰 , YOU WILL WIN ❗ ️. YOU WILL DO ALL OF THAT 💯 , YOU UNDERSTAND ⁉ ️ YOU WILL BECOME A BILLIONAIRE 💵 📈 AND REBUILD YOUR FUCKING LIFE 🤯` - } else { - text = `🦍 🗣️ DO NOT GET IT TWISTED 🌪️ , DO NOT GAMBLE 🚫 . DO NOT START GAMBLING ❌ . GAMBLING IS ENTERTAINMENT 🎰 AND ENTERTAINMENT ONLY 👍 . YOU WONT BREAK EVEN 🛑 , YOU WONT WIN ⚠️ ️. YOU WONT DO ANY OF THAT 💯 , YOU UNDERSTAND ⁉️ ️ YOU WILL ONLY GO INTO DEBT 💵 📉 AND RUIN YOUR FUCKING LIFE 😵` - } + text := dgoutils.Ternary(getItTwisted, + `🦍 🗣 GET IT TWISTED 🌪 , GAMBLE ✅ . PLEASE START GAMBLING 👍 . GAMBLING IS AN INVESTMENT 🎰 AND AN INVESTMENT ONLY 👍 . YOU WILL PROFIT 💰 , YOU WILL WIN ❗ ️. YOU WILL DO ALL OF THAT 💯 , YOU UNDERSTAND ⁉ ️ YOU WILL BECOME A BILLIONAIRE 💵 📈 AND REBUILD YOUR FUCKING LIFE 🤯`, + `🦍 🗣️ DO NOT GET IT TWISTED 🌪️ , DO NOT GAMBLE 🚫 . DO NOT START GAMBLING ❌ . GAMBLING IS ENTERTAINMENT 🎰 AND ENTERTAINMENT ONLY 👍 . YOU WONT BREAK EVEN 🛑 , YOU WONT WIN ⚠️ ️. YOU WONT DO ANY OF THAT 💯 , YOU UNDERSTAND ⁉️ ️ YOU WILL ONLY GO INTO DEBT 💵 📉 AND RUIN YOUR FUCKING LIFE 😵`, + ) return gctx.Reply(text) } diff --git a/commands/settings.go b/commands/settings.go index d2f26a8..66ed533 100644 --- a/commands/settings.go +++ b/commands/settings.go @@ -161,18 +161,16 @@ func set(b *bot.Bot) func(*gumi.Ctx) error { ), ) - var artChannels []string - if len(guild.ArtChannels) > 5 { - artChannels = []string{"There are more than 5 art channels, use `bt!artchannels` command to see them."} - } else { - artChannels = arrays.Map(guild.ArtChannels, func(s string) string { + channels := dgoutils.Ternary(len(guild.ArtChannels) > 5, + []string{"There are more than 5 art channels, use `bt!artchannels` command to see them."}, + arrays.Map(guild.ArtChannels, func(s string) string { return fmt.Sprintf("<#%v> | `%v`", s, s) - }) - } + }), + ) eb.AddField( "Art channels", - "Use `bt!artchannels` command to list or manage art channels!\n\n"+strings.Join(artChannels, "\n"), + "Use `bt!artchannels` command to list or manage art channels!\n\n"+strings.Join(channels, "\n"), ) return gctx.ReplyEmbed(eb.Finalize()) diff --git a/commands/user.go b/commands/user.go index 4af3112..9b5c0f7 100644 --- a/commands/user.go +++ b/commands/user.go @@ -398,7 +398,7 @@ func push(b *bot.Bot) func(*gumi.Ctx) error { continue } - if arrays.Any(group.Children, channelID) { + if arrays.Check(channelID, group.Children) { continue } @@ -452,7 +452,7 @@ func remove(b *bot.Bot) func(*gumi.Ctx) error { for arg := range gctx.Args.Arguments { channelID := dgoutils.Trimmer(gctx, arg) - if !arrays.Any(group.Children, channelID) { + if !arrays.Check(channelID, group.Children) { continue } @@ -506,7 +506,7 @@ func editParent(b *bot.Bot) func(*gumi.Ctx) error { return messages.ErrGroupAlreadyExists(dest) } - if arrays.Any(group.Children, dest) { + if arrays.Check(dest, group.Children) { return messages.ErrUserEditParentFail(group.Parent, dest) } diff --git a/handlers/handlers.go b/handlers/handlers.go index fcbc4a3..685ced6 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -70,7 +70,7 @@ func OnMessage(b *bot.Bot) func(*gumi.Ctx) error { return err } - if !(len(guild.ArtChannels) == 0 || arrays.Any(guild.ArtChannels, gctx.Event.ChannelID)) { + if !(len(guild.ArtChannels) == 0 || arrays.Check(gctx.Event.ChannelID, guild.ArtChannels)) { return nil } diff --git a/internal/arrays/arrays.go b/internal/arrays/arrays.go index 2a79de7..4c75b74 100644 --- a/internal/arrays/arrays.go +++ b/internal/arrays/arrays.go @@ -5,9 +5,15 @@ import ( "time" ) -func Any[T comparable](slice []T, cmp T) bool { +func collate[T comparable](a, b T, c ...T) []T { + slice := make([]T, 0) + slice = append(slice, a, b) + return append(slice, c...) +} + +func Check[T comparable](compare T, slice []T) bool { for _, val := range slice { - if val == cmp { + if val == compare { return true } } @@ -15,7 +21,11 @@ func Any[T comparable](slice []T, cmp T) bool { return false } -func AnyFunc[T comparable](slice []T, f func(T) bool) bool { +func CheckArgs[T comparable](compare, a, b T, c ...T) bool { + return Check(compare, collate(a, b, c...)) +} + +func CheckFunc[T comparable](f func(T) bool, slice []T) bool { for _, val := range slice { if f(val) { return true @@ -25,6 +35,48 @@ func AnyFunc[T comparable](slice []T, f func(T) bool) bool { return false } +func CheckFuncArgs[T comparable](f func(T) bool, a, b T, c ...T) bool { + return CheckFunc(f, collate(a, b, c...)) +} + +func CheckFuncCompare[T comparable](f func(T, T) bool, compare T, slice []T) bool { + for _, val := range slice { + if f(compare, val) { + return true + } + } + + return false +} + +func CheckFuncCompareArgs[T comparable](f func(T, T) bool, compare, a, b T, c ...T) bool { + return CheckFuncCompare(f, compare, collate(a, b, c...)) +} + +func CheckArrays[T comparable](a, b []T) bool { + for _, val := range a { + for _, test := range b { + if val == test { + return true + } + } + } + + return false +} + +func CheckArraysFunc[T comparable](f func(T, T) bool, a, b []T) bool { + for _, val := range a { + for _, test := range b { + if f(val, test) { + return true + } + } + } + + return false +} + func Filter[T any](slice []T, f func(T) bool) []T { filtered := make([]T, 0) diff --git a/internal/dgoutils/dgoutils.go b/internal/dgoutils/dgoutils.go index 5e40ac8..abaddb5 100644 --- a/internal/dgoutils/dgoutils.go +++ b/internal/dgoutils/dgoutils.go @@ -27,6 +27,14 @@ func Ternary[T any](condition bool, a T, b T) T { return b } +func TernaryFunc[T any](f func(T), condition bool, a T, b T) { + if condition { + f(a) + } + + f(b) +} + func ValidateArgs(gctx *gumi.Ctx, argsLen int) error { if gctx.Args.Len() < argsLen { return messages.ErrIncorrectCmd(gctx.Command) @@ -132,7 +140,7 @@ func (r *Range) Array() []int { } func (r *Range) Map() map[int]struct{} { - m := make(map[int]struct{}, 0) + m := make(map[int]struct{}) for i := r.Low; i <= r.High; i++ { m[i] = struct{}{} } diff --git a/post/post.go b/post/post.go index 90d6f98..f84228f 100644 --- a/post/post.go +++ b/post/post.go @@ -169,7 +169,7 @@ func (p *Post) Crosspost(ctx context.Context, userID string, group *store.Group) "group", group, "channel_id", channelID, ) - + go func(channelID string) { defer wg.Done() ch, err := p.Ctx.Session.Channel(channelID) @@ -194,7 +194,7 @@ func (p *Post) Crosspost(ctx context.Context, userID string, group *store.Group) } if guild.Crosspost { - if len(guild.ArtChannels) == 0 || arrays.Any(guild.ArtChannels, ch.ID) { + if len(guild.ArtChannels) == 0 || arrays.Check(ch.ID, guild.ArtChannels) { p.CrosspostMode = true res, err := p.fetch(ctx, guild, channelID) if err != nil { @@ -207,7 +207,7 @@ func (p *Post) Crosspost(ctx context.Context, userID string, group *store.Group) log.With("error", err).Error("failed to send messages") return } - + msgChan <- sent } } diff --git a/store/users.go b/store/users.go index 14e51a6..17e17fa 100644 --- a/store/users.go +++ b/store/users.go @@ -52,7 +52,7 @@ func DefaultUser(id string) *User { func (u *User) FindGroup(channelID string) (*Group, bool) { for _, group := range u.Groups { if group.IsPair { - if arrays.Any(group.Children, channelID) { + if arrays.Check(channelID, group.Children) { return group, true } From 16306a83bc45160d57f686e056d038b443b7523a Mon Sep 17 00:00:00 2001 From: XangelMusic Date: Wed, 12 Jun 2024 01:46:36 +0800 Subject: [PATCH 11/30] boost: added Slices pkg --- artworks/artworks.go | 10 ++---- artworks/deviant/deviant.go | 2 +- artworks/pixiv/pixiv.go | 56 +++++++++++++-------------------- commands/general.go | 5 ++- commands/memes.go | 10 +++--- commands/settings.go | 14 ++++----- commands/user.go | 6 ++-- handlers/handlers.go | 2 +- internal/arrays/arrays.go | 58 +++++++++++++++++++++++++++++++++-- internal/dgoutils/dgoutils.go | 10 +++++- post/post.go | 6 ++-- store/users.go | 2 +- 12 files changed, 109 insertions(+), 72 deletions(-) diff --git a/artworks/artworks.go b/artworks/artworks.go index 1c8c122..3761c25 100644 --- a/artworks/artworks.go +++ b/artworks/artworks.go @@ -1,6 +1,7 @@ package artworks import ( + "github.com/VTGare/boe-tea-go/internal/arrays" "strings" "github.com/VTGare/boe-tea-go/store" @@ -32,12 +33,5 @@ func IsAIGenerated(content ...string) bool { "stablediffusion", } - for _, tag := range content { - for _, test := range aiTags { - if strings.EqualFold(tag, test) { - return true - } - } - } - return false + return arrays.CheckArraysFunc(strings.EqualFold, content, aiTags) } diff --git a/artworks/deviant/deviant.go b/artworks/deviant/deviant.go index fdf9680..9d7c37d 100644 --- a/artworks/deviant/deviant.go +++ b/artworks/deviant/deviant.go @@ -64,7 +64,7 @@ type deviantEmbed struct { func New() artworks.Provider { return &DeviantArt{ - regex: regexp.MustCompile(`(?i)https://(?:www\.)?deviantart\.com/[\w]+/art/([\w\-]+)`), + regex: regexp.MustCompile(`(?i)https://(?:www\.)?deviantart\.com/\w+/art/([\w\-]+)`), } } diff --git a/artworks/pixiv/pixiv.go b/artworks/pixiv/pixiv.go index bc5c680..5f27c83 100644 --- a/artworks/pixiv/pixiv.go +++ b/artworks/pixiv/pixiv.go @@ -2,14 +2,15 @@ package pixiv import ( "fmt" - "github.com/VTGare/boe-tea-go/artworks/embed" "regexp" "strconv" "strings" "time" "github.com/VTGare/boe-tea-go/artworks" + "github.com/VTGare/boe-tea-go/artworks/embed" "github.com/VTGare/boe-tea-go/internal/arrays" + "github.com/VTGare/boe-tea-go/internal/dgoutils" "github.com/VTGare/boe-tea-go/messages" "github.com/VTGare/boe-tea-go/store" "github.com/bwmarrin/discordgo" @@ -89,13 +90,6 @@ func (p *Pixiv) Find(id string) (artworks.Artwork, error) { return nil, artworks.ErrArtworkNotFound } - author := "" - if illust.User != nil { - author = illust.User.Name - } else { - author = "Unknown" - } - tags := make([]string, 0) nsfw := false for _, tag := range illust.Tags { @@ -103,11 +97,10 @@ func (p *Pixiv) Find(id string) (artworks.Artwork, error) { nsfw = true } - if tag.TranslatedName != "" { - tags = append(tags, tag.TranslatedName) - } else { - tags = append(tags, tag.Name) - } + tags = dgoutils.Ternary(tag.TranslatedName != "", + append(tags, tag.TranslatedName), + append(tags, tag.Name), + ) } images := make([]*Image, 0, illust.PageCount) @@ -131,38 +124,33 @@ func (p *Pixiv) Find(id string) (artworks.Artwork, error) { images = append(images, img) } - artwork := &Artwork{ - ID: id, - url: "https://www.pixiv.net/en/artworks/" + id, - Title: illust.Title, - Author: author, - Tags: tags, - Images: images, - NSFW: nsfw, - Type: illust.Type, - Pages: illust.PageCount, - Likes: illust.TotalBookmarks, - CreatedAt: illust.CreateDate, - - proxy: p.proxyHost, - } - errImages := []string{ "limit_sanity_level_360.png", "limit_unknown_360.png", } for _, img := range errImages { - if artwork.Images[0].Original == fmt.Sprintf("https://s.pximg.net/common/images/%s", img) { + if images[0].Original == fmt.Sprintf("https://s.pximg.net/common/images/%s", img) { return nil, artworks.ErrRateLimited } } - if illust.IllustAIType == pixiv.IllustAITypeAIGenerated { - artwork.AIGenerated = true - } + return &Artwork{ + ID: id, + url: "https://www.pixiv.net/en/artworks/" + id, + Title: illust.Title, + Author: dgoutils.Ternary(illust.User != nil, illust.User.Name, "Unknown"), + Tags: tags, + Images: images, + NSFW: nsfw, + Type: illust.Type, + Pages: illust.PageCount, + Likes: illust.TotalBookmarks, + CreatedAt: illust.CreateDate, + AIGenerated: illust.IllustAIType == pixiv.IllustAITypeAIGenerated, - return artwork, nil + proxy: p.proxyHost, + }, nil }) } diff --git a/commands/general.go b/commands/general.go index 6265204..60d0ed7 100644 --- a/commands/general.go +++ b/commands/general.go @@ -243,9 +243,8 @@ func feedback(*bot.Bot) func(*gumi.Ctx) error { if len(gctx.Event.Attachments) > 0 { att := gctx.Event.Attachments[0] - if strings.HasSuffix(att.Filename, "png") || - strings.HasSuffix(att.Filename, "jpg") || - strings.HasSuffix(att.Filename, "gif") { + if arrays.CheckFuncCompareArgs( + strings.HasSuffix, att.Filename, "png", "jpg", "gif") { eb.Image(att.URL) } } diff --git a/commands/memes.go b/commands/memes.go index a080a83..be3dfe9 100644 --- a/commands/memes.go +++ b/commands/memes.go @@ -173,12 +173,10 @@ func gamba(*bot.Bot) func(*gumi.Ctx) error { return func(gctx *gumi.Ctx) error { getItTwisted := rand.Intn(10) != 0 - var text string - if getItTwisted { - text = `🦍 🗣 GET IT TWISTED 🌪 , GAMBLE ✅ . PLEASE START GAMBLING 👍 . GAMBLING IS AN INVESTMENT 🎰 AND AN INVESTMENT ONLY 👍 . YOU WILL PROFIT 💰 , YOU WILL WIN ❗ ️. YOU WILL DO ALL OF THAT 💯 , YOU UNDERSTAND ⁉ ️ YOU WILL BECOME A BILLIONAIRE 💵 📈 AND REBUILD YOUR FUCKING LIFE 🤯` - } else { - text = `🦍 🗣️ DO NOT GET IT TWISTED 🌪️ , DO NOT GAMBLE 🚫 . DO NOT START GAMBLING ❌ . GAMBLING IS ENTERTAINMENT 🎰 AND ENTERTAINMENT ONLY 👍 . YOU WONT BREAK EVEN 🛑 , YOU WONT WIN ⚠️ ️. YOU WONT DO ANY OF THAT 💯 , YOU UNDERSTAND ⁉️ ️ YOU WILL ONLY GO INTO DEBT 💵 📉 AND RUIN YOUR FUCKING LIFE 😵` - } + text := dgoutils.Ternary(getItTwisted, + `🦍 🗣 GET IT TWISTED 🌪 , GAMBLE ✅ . PLEASE START GAMBLING 👍 . GAMBLING IS AN INVESTMENT 🎰 AND AN INVESTMENT ONLY 👍 . YOU WILL PROFIT 💰 , YOU WILL WIN ❗ ️. YOU WILL DO ALL OF THAT 💯 , YOU UNDERSTAND ⁉ ️ YOU WILL BECOME A BILLIONAIRE 💵 📈 AND REBUILD YOUR FUCKING LIFE 🤯`, + `🦍 🗣️ DO NOT GET IT TWISTED 🌪️ , DO NOT GAMBLE 🚫 . DO NOT START GAMBLING ❌ . GAMBLING IS ENTERTAINMENT 🎰 AND ENTERTAINMENT ONLY 👍 . YOU WONT BREAK EVEN 🛑 , YOU WONT WIN ⚠️ ️. YOU WONT DO ANY OF THAT 💯 , YOU UNDERSTAND ⁉️ ️ YOU WILL ONLY GO INTO DEBT 💵 📉 AND RUIN YOUR FUCKING LIFE 😵`, + ) return gctx.Reply(text) } diff --git a/commands/settings.go b/commands/settings.go index d2f26a8..66ed533 100644 --- a/commands/settings.go +++ b/commands/settings.go @@ -161,18 +161,16 @@ func set(b *bot.Bot) func(*gumi.Ctx) error { ), ) - var artChannels []string - if len(guild.ArtChannels) > 5 { - artChannels = []string{"There are more than 5 art channels, use `bt!artchannels` command to see them."} - } else { - artChannels = arrays.Map(guild.ArtChannels, func(s string) string { + channels := dgoutils.Ternary(len(guild.ArtChannels) > 5, + []string{"There are more than 5 art channels, use `bt!artchannels` command to see them."}, + arrays.Map(guild.ArtChannels, func(s string) string { return fmt.Sprintf("<#%v> | `%v`", s, s) - }) - } + }), + ) eb.AddField( "Art channels", - "Use `bt!artchannels` command to list or manage art channels!\n\n"+strings.Join(artChannels, "\n"), + "Use `bt!artchannels` command to list or manage art channels!\n\n"+strings.Join(channels, "\n"), ) return gctx.ReplyEmbed(eb.Finalize()) diff --git a/commands/user.go b/commands/user.go index 4af3112..9b5c0f7 100644 --- a/commands/user.go +++ b/commands/user.go @@ -398,7 +398,7 @@ func push(b *bot.Bot) func(*gumi.Ctx) error { continue } - if arrays.Any(group.Children, channelID) { + if arrays.Check(channelID, group.Children) { continue } @@ -452,7 +452,7 @@ func remove(b *bot.Bot) func(*gumi.Ctx) error { for arg := range gctx.Args.Arguments { channelID := dgoutils.Trimmer(gctx, arg) - if !arrays.Any(group.Children, channelID) { + if !arrays.Check(channelID, group.Children) { continue } @@ -506,7 +506,7 @@ func editParent(b *bot.Bot) func(*gumi.Ctx) error { return messages.ErrGroupAlreadyExists(dest) } - if arrays.Any(group.Children, dest) { + if arrays.Check(dest, group.Children) { return messages.ErrUserEditParentFail(group.Parent, dest) } diff --git a/handlers/handlers.go b/handlers/handlers.go index fcbc4a3..685ced6 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -70,7 +70,7 @@ func OnMessage(b *bot.Bot) func(*gumi.Ctx) error { return err } - if !(len(guild.ArtChannels) == 0 || arrays.Any(guild.ArtChannels, gctx.Event.ChannelID)) { + if !(len(guild.ArtChannels) == 0 || arrays.Check(gctx.Event.ChannelID, guild.ArtChannels)) { return nil } diff --git a/internal/arrays/arrays.go b/internal/arrays/arrays.go index 2a79de7..4c75b74 100644 --- a/internal/arrays/arrays.go +++ b/internal/arrays/arrays.go @@ -5,9 +5,15 @@ import ( "time" ) -func Any[T comparable](slice []T, cmp T) bool { +func collate[T comparable](a, b T, c ...T) []T { + slice := make([]T, 0) + slice = append(slice, a, b) + return append(slice, c...) +} + +func Check[T comparable](compare T, slice []T) bool { for _, val := range slice { - if val == cmp { + if val == compare { return true } } @@ -15,7 +21,11 @@ func Any[T comparable](slice []T, cmp T) bool { return false } -func AnyFunc[T comparable](slice []T, f func(T) bool) bool { +func CheckArgs[T comparable](compare, a, b T, c ...T) bool { + return Check(compare, collate(a, b, c...)) +} + +func CheckFunc[T comparable](f func(T) bool, slice []T) bool { for _, val := range slice { if f(val) { return true @@ -25,6 +35,48 @@ func AnyFunc[T comparable](slice []T, f func(T) bool) bool { return false } +func CheckFuncArgs[T comparable](f func(T) bool, a, b T, c ...T) bool { + return CheckFunc(f, collate(a, b, c...)) +} + +func CheckFuncCompare[T comparable](f func(T, T) bool, compare T, slice []T) bool { + for _, val := range slice { + if f(compare, val) { + return true + } + } + + return false +} + +func CheckFuncCompareArgs[T comparable](f func(T, T) bool, compare, a, b T, c ...T) bool { + return CheckFuncCompare(f, compare, collate(a, b, c...)) +} + +func CheckArrays[T comparable](a, b []T) bool { + for _, val := range a { + for _, test := range b { + if val == test { + return true + } + } + } + + return false +} + +func CheckArraysFunc[T comparable](f func(T, T) bool, a, b []T) bool { + for _, val := range a { + for _, test := range b { + if f(val, test) { + return true + } + } + } + + return false +} + func Filter[T any](slice []T, f func(T) bool) []T { filtered := make([]T, 0) diff --git a/internal/dgoutils/dgoutils.go b/internal/dgoutils/dgoutils.go index 5e40ac8..abaddb5 100644 --- a/internal/dgoutils/dgoutils.go +++ b/internal/dgoutils/dgoutils.go @@ -27,6 +27,14 @@ func Ternary[T any](condition bool, a T, b T) T { return b } +func TernaryFunc[T any](f func(T), condition bool, a T, b T) { + if condition { + f(a) + } + + f(b) +} + func ValidateArgs(gctx *gumi.Ctx, argsLen int) error { if gctx.Args.Len() < argsLen { return messages.ErrIncorrectCmd(gctx.Command) @@ -132,7 +140,7 @@ func (r *Range) Array() []int { } func (r *Range) Map() map[int]struct{} { - m := make(map[int]struct{}, 0) + m := make(map[int]struct{}) for i := r.Low; i <= r.High; i++ { m[i] = struct{}{} } diff --git a/post/post.go b/post/post.go index 90d6f98..f84228f 100644 --- a/post/post.go +++ b/post/post.go @@ -169,7 +169,7 @@ func (p *Post) Crosspost(ctx context.Context, userID string, group *store.Group) "group", group, "channel_id", channelID, ) - + go func(channelID string) { defer wg.Done() ch, err := p.Ctx.Session.Channel(channelID) @@ -194,7 +194,7 @@ func (p *Post) Crosspost(ctx context.Context, userID string, group *store.Group) } if guild.Crosspost { - if len(guild.ArtChannels) == 0 || arrays.Any(guild.ArtChannels, ch.ID) { + if len(guild.ArtChannels) == 0 || arrays.Check(ch.ID, guild.ArtChannels) { p.CrosspostMode = true res, err := p.fetch(ctx, guild, channelID) if err != nil { @@ -207,7 +207,7 @@ func (p *Post) Crosspost(ctx context.Context, userID string, group *store.Group) log.With("error", err).Error("failed to send messages") return } - + msgChan <- sent } } diff --git a/store/users.go b/store/users.go index 14e51a6..17e17fa 100644 --- a/store/users.go +++ b/store/users.go @@ -52,7 +52,7 @@ func DefaultUser(id string) *User { func (u *User) FindGroup(channelID string) (*Group, bool) { for _, group := range u.Groups { if group.IsPair { - if arrays.Any(group.Children, channelID) { + if arrays.Check(channelID, group.Children) { return group, true } From 23bdab7b8babcb04d4386c60467d03885a77850f Mon Sep 17 00:00:00 2001 From: XangelMusic Date: Thu, 12 Sep 2024 22:43:12 +0800 Subject: [PATCH 12/30] boost: added Slices pkg --- artworks/artworks.go | 13 +++++-- commands/user.go | 7 ++-- handlers/handlers.go | 4 +- internal/arrays/arrays.go | 72 ----------------------------------- internal/dgoutils/dgoutils.go | 8 ---- post/post.go | 3 +- store/users.go | 5 +-- 7 files changed, 19 insertions(+), 93 deletions(-) diff --git a/artworks/artworks.go b/artworks/artworks.go index 3761c25..37516c5 100644 --- a/artworks/artworks.go +++ b/artworks/artworks.go @@ -1,11 +1,9 @@ package artworks import ( - "github.com/VTGare/boe-tea-go/internal/arrays" - "strings" - "github.com/VTGare/boe-tea-go/store" "github.com/bwmarrin/discordgo" + "strings" ) type Provider interface { @@ -33,5 +31,12 @@ func IsAIGenerated(content ...string) bool { "stablediffusion", } - return arrays.CheckArraysFunc(strings.EqualFold, content, aiTags) + for _, tag := range content { + for _, test := range aiTags { + if strings.EqualFold(tag, test) { + return true + } + } + } + return false } diff --git a/commands/user.go b/commands/user.go index 9b5c0f7..e3d30e8 100644 --- a/commands/user.go +++ b/commands/user.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "slices" "sort" "strconv" "strings" @@ -398,7 +399,7 @@ func push(b *bot.Bot) func(*gumi.Ctx) error { continue } - if arrays.Check(channelID, group.Children) { + if slices.Contains(group.Children, channelID) { continue } @@ -452,7 +453,7 @@ func remove(b *bot.Bot) func(*gumi.Ctx) error { for arg := range gctx.Args.Arguments { channelID := dgoutils.Trimmer(gctx, arg) - if !arrays.Check(channelID, group.Children) { + if !slices.Contains(group.Children, channelID) { continue } @@ -506,7 +507,7 @@ func editParent(b *bot.Bot) func(*gumi.Ctx) error { return messages.ErrGroupAlreadyExists(dest) } - if arrays.Check(dest, group.Children) { + if slices.Contains(group.Children, dest) { return messages.ErrUserEditParentFail(group.Parent, dest) } diff --git a/handlers/handlers.go b/handlers/handlers.go index 685ced6..aafa2b1 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "slices" "strconv" "strings" "time" @@ -11,7 +12,6 @@ import ( "github.com/VTGare/boe-tea-go/artworks" "github.com/VTGare/boe-tea-go/artworks/twitter" "github.com/VTGare/boe-tea-go/bot" - "github.com/VTGare/boe-tea-go/internal/arrays" "github.com/VTGare/boe-tea-go/internal/cache" "github.com/VTGare/boe-tea-go/internal/dgoutils" "github.com/VTGare/boe-tea-go/messages" @@ -70,7 +70,7 @@ func OnMessage(b *bot.Bot) func(*gumi.Ctx) error { return err } - if !(len(guild.ArtChannels) == 0 || arrays.Check(gctx.Event.ChannelID, guild.ArtChannels)) { + if !(len(guild.ArtChannels) == 0 || slices.Contains(guild.ArtChannels, gctx.Event.ChannelID)) { return nil } diff --git a/internal/arrays/arrays.go b/internal/arrays/arrays.go index 4c75b74..7486bdd 100644 --- a/internal/arrays/arrays.go +++ b/internal/arrays/arrays.go @@ -5,78 +5,6 @@ import ( "time" ) -func collate[T comparable](a, b T, c ...T) []T { - slice := make([]T, 0) - slice = append(slice, a, b) - return append(slice, c...) -} - -func Check[T comparable](compare T, slice []T) bool { - for _, val := range slice { - if val == compare { - return true - } - } - - return false -} - -func CheckArgs[T comparable](compare, a, b T, c ...T) bool { - return Check(compare, collate(a, b, c...)) -} - -func CheckFunc[T comparable](f func(T) bool, slice []T) bool { - for _, val := range slice { - if f(val) { - return true - } - } - - return false -} - -func CheckFuncArgs[T comparable](f func(T) bool, a, b T, c ...T) bool { - return CheckFunc(f, collate(a, b, c...)) -} - -func CheckFuncCompare[T comparable](f func(T, T) bool, compare T, slice []T) bool { - for _, val := range slice { - if f(compare, val) { - return true - } - } - - return false -} - -func CheckFuncCompareArgs[T comparable](f func(T, T) bool, compare, a, b T, c ...T) bool { - return CheckFuncCompare(f, compare, collate(a, b, c...)) -} - -func CheckArrays[T comparable](a, b []T) bool { - for _, val := range a { - for _, test := range b { - if val == test { - return true - } - } - } - - return false -} - -func CheckArraysFunc[T comparable](f func(T, T) bool, a, b []T) bool { - for _, val := range a { - for _, test := range b { - if f(val, test) { - return true - } - } - } - - return false -} - func Filter[T any](slice []T, f func(T) bool) []T { filtered := make([]T, 0) diff --git a/internal/dgoutils/dgoutils.go b/internal/dgoutils/dgoutils.go index abaddb5..6771aa5 100644 --- a/internal/dgoutils/dgoutils.go +++ b/internal/dgoutils/dgoutils.go @@ -27,14 +27,6 @@ func Ternary[T any](condition bool, a T, b T) T { return b } -func TernaryFunc[T any](f func(T), condition bool, a T, b T) { - if condition { - f(a) - } - - f(b) -} - func ValidateArgs(gctx *gumi.Ctx, argsLen int) error { if gctx.Args.Len() < argsLen { return messages.ErrIncorrectCmd(gctx.Command) diff --git a/post/post.go b/post/post.go index f84228f..d03e201 100644 --- a/post/post.go +++ b/post/post.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "reflect" + "slices" "strconv" "strings" "sync" @@ -194,7 +195,7 @@ func (p *Post) Crosspost(ctx context.Context, userID string, group *store.Group) } if guild.Crosspost { - if len(guild.ArtChannels) == 0 || arrays.Check(ch.ID, guild.ArtChannels) { + if len(guild.ArtChannels) == 0 || slices.Contains(guild.ArtChannels, ch.ID) { p.CrosspostMode = true res, err := p.fetch(ctx, guild, channelID) if err != nil { diff --git a/store/users.go b/store/users.go index 17e17fa..5b8886c 100644 --- a/store/users.go +++ b/store/users.go @@ -2,9 +2,8 @@ package store import ( "context" + "slices" "time" - - "github.com/VTGare/boe-tea-go/internal/arrays" ) type UserStore interface { @@ -52,7 +51,7 @@ func DefaultUser(id string) *User { func (u *User) FindGroup(channelID string) (*Group, bool) { for _, group := range u.Groups { if group.IsPair { - if arrays.Check(channelID, group.Children) { + if slices.Contains(group.Children, channelID) { return group, true } From 93db9156a9853d32684b37912bd8644a71870eb2 Mon Sep 17 00:00:00 2001 From: XangelMusic Date: Thu, 12 Sep 2024 22:43:12 +0800 Subject: [PATCH 13/30] boost: added Slices pkg --- artworks/artworks.go | 13 +++++-- commands/general.go | 8 ++-- commands/user.go | 7 ++-- handlers/handlers.go | 4 +- internal/arrays/arrays.go | 72 ----------------------------------- internal/dgoutils/dgoutils.go | 8 ---- post/post.go | 3 +- store/users.go | 5 +-- 8 files changed, 24 insertions(+), 96 deletions(-) diff --git a/artworks/artworks.go b/artworks/artworks.go index 3761c25..37516c5 100644 --- a/artworks/artworks.go +++ b/artworks/artworks.go @@ -1,11 +1,9 @@ package artworks import ( - "github.com/VTGare/boe-tea-go/internal/arrays" - "strings" - "github.com/VTGare/boe-tea-go/store" "github.com/bwmarrin/discordgo" + "strings" ) type Provider interface { @@ -33,5 +31,12 @@ func IsAIGenerated(content ...string) bool { "stablediffusion", } - return arrays.CheckArraysFunc(strings.EqualFold, content, aiTags) + for _, tag := range content { + for _, test := range aiTags { + if strings.EqualFold(tag, test) { + return true + } + } + } + return false } diff --git a/commands/general.go b/commands/general.go index 60d0ed7..f044334 100644 --- a/commands/general.go +++ b/commands/general.go @@ -243,9 +243,11 @@ func feedback(*bot.Bot) func(*gumi.Ctx) error { if len(gctx.Event.Attachments) > 0 { att := gctx.Event.Attachments[0] - if arrays.CheckFuncCompareArgs( - strings.HasSuffix, att.Filename, "png", "jpg", "gif") { - eb.Image(att.URL) + + for _, suffix := range []string{"png", "jpg", "jpeg", "gif"} { + if strings.HasSuffix(att.Filename, suffix) { + eb.Image(att.URL) + } } } diff --git a/commands/user.go b/commands/user.go index 9b5c0f7..e3d30e8 100644 --- a/commands/user.go +++ b/commands/user.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "slices" "sort" "strconv" "strings" @@ -398,7 +399,7 @@ func push(b *bot.Bot) func(*gumi.Ctx) error { continue } - if arrays.Check(channelID, group.Children) { + if slices.Contains(group.Children, channelID) { continue } @@ -452,7 +453,7 @@ func remove(b *bot.Bot) func(*gumi.Ctx) error { for arg := range gctx.Args.Arguments { channelID := dgoutils.Trimmer(gctx, arg) - if !arrays.Check(channelID, group.Children) { + if !slices.Contains(group.Children, channelID) { continue } @@ -506,7 +507,7 @@ func editParent(b *bot.Bot) func(*gumi.Ctx) error { return messages.ErrGroupAlreadyExists(dest) } - if arrays.Check(dest, group.Children) { + if slices.Contains(group.Children, dest) { return messages.ErrUserEditParentFail(group.Parent, dest) } diff --git a/handlers/handlers.go b/handlers/handlers.go index 685ced6..aafa2b1 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "slices" "strconv" "strings" "time" @@ -11,7 +12,6 @@ import ( "github.com/VTGare/boe-tea-go/artworks" "github.com/VTGare/boe-tea-go/artworks/twitter" "github.com/VTGare/boe-tea-go/bot" - "github.com/VTGare/boe-tea-go/internal/arrays" "github.com/VTGare/boe-tea-go/internal/cache" "github.com/VTGare/boe-tea-go/internal/dgoutils" "github.com/VTGare/boe-tea-go/messages" @@ -70,7 +70,7 @@ func OnMessage(b *bot.Bot) func(*gumi.Ctx) error { return err } - if !(len(guild.ArtChannels) == 0 || arrays.Check(gctx.Event.ChannelID, guild.ArtChannels)) { + if !(len(guild.ArtChannels) == 0 || slices.Contains(guild.ArtChannels, gctx.Event.ChannelID)) { return nil } diff --git a/internal/arrays/arrays.go b/internal/arrays/arrays.go index 4c75b74..7486bdd 100644 --- a/internal/arrays/arrays.go +++ b/internal/arrays/arrays.go @@ -5,78 +5,6 @@ import ( "time" ) -func collate[T comparable](a, b T, c ...T) []T { - slice := make([]T, 0) - slice = append(slice, a, b) - return append(slice, c...) -} - -func Check[T comparable](compare T, slice []T) bool { - for _, val := range slice { - if val == compare { - return true - } - } - - return false -} - -func CheckArgs[T comparable](compare, a, b T, c ...T) bool { - return Check(compare, collate(a, b, c...)) -} - -func CheckFunc[T comparable](f func(T) bool, slice []T) bool { - for _, val := range slice { - if f(val) { - return true - } - } - - return false -} - -func CheckFuncArgs[T comparable](f func(T) bool, a, b T, c ...T) bool { - return CheckFunc(f, collate(a, b, c...)) -} - -func CheckFuncCompare[T comparable](f func(T, T) bool, compare T, slice []T) bool { - for _, val := range slice { - if f(compare, val) { - return true - } - } - - return false -} - -func CheckFuncCompareArgs[T comparable](f func(T, T) bool, compare, a, b T, c ...T) bool { - return CheckFuncCompare(f, compare, collate(a, b, c...)) -} - -func CheckArrays[T comparable](a, b []T) bool { - for _, val := range a { - for _, test := range b { - if val == test { - return true - } - } - } - - return false -} - -func CheckArraysFunc[T comparable](f func(T, T) bool, a, b []T) bool { - for _, val := range a { - for _, test := range b { - if f(val, test) { - return true - } - } - } - - return false -} - func Filter[T any](slice []T, f func(T) bool) []T { filtered := make([]T, 0) diff --git a/internal/dgoutils/dgoutils.go b/internal/dgoutils/dgoutils.go index abaddb5..6771aa5 100644 --- a/internal/dgoutils/dgoutils.go +++ b/internal/dgoutils/dgoutils.go @@ -27,14 +27,6 @@ func Ternary[T any](condition bool, a T, b T) T { return b } -func TernaryFunc[T any](f func(T), condition bool, a T, b T) { - if condition { - f(a) - } - - f(b) -} - func ValidateArgs(gctx *gumi.Ctx, argsLen int) error { if gctx.Args.Len() < argsLen { return messages.ErrIncorrectCmd(gctx.Command) diff --git a/post/post.go b/post/post.go index f84228f..d03e201 100644 --- a/post/post.go +++ b/post/post.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "reflect" + "slices" "strconv" "strings" "sync" @@ -194,7 +195,7 @@ func (p *Post) Crosspost(ctx context.Context, userID string, group *store.Group) } if guild.Crosspost { - if len(guild.ArtChannels) == 0 || arrays.Check(ch.ID, guild.ArtChannels) { + if len(guild.ArtChannels) == 0 || slices.Contains(guild.ArtChannels, ch.ID) { p.CrosspostMode = true res, err := p.fetch(ctx, guild, channelID) if err != nil { diff --git a/store/users.go b/store/users.go index 17e17fa..5b8886c 100644 --- a/store/users.go +++ b/store/users.go @@ -2,9 +2,8 @@ package store import ( "context" + "slices" "time" - - "github.com/VTGare/boe-tea-go/internal/arrays" ) type UserStore interface { @@ -52,7 +51,7 @@ func DefaultUser(id string) *User { func (u *User) FindGroup(channelID string) (*Group, bool) { for _, group := range u.Groups { if group.IsPair { - if arrays.Check(channelID, group.Children) { + if slices.Contains(group.Children, channelID) { return group, true } From 975e236873db1d29ff547cef1b45be5328f3e22b Mon Sep 17 00:00:00 2001 From: XangelMusic Date: Wed, 18 Sep 2024 04:03:19 +0800 Subject: [PATCH 14/30] refactor: Trimmer functions --- commands/settings.go | 8 ++++---- commands/user.go | 4 ++-- internal/dgoutils/dgoutils.go | 5 +++++ post/post.go | 4 ++-- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/commands/settings.go b/commands/settings.go index 66ed533..ab7efee 100644 --- a/commands/settings.go +++ b/commands/settings.go @@ -492,8 +492,8 @@ func artChannels(b *bot.Bot) func(*gumi.Ctx) error { } channels := make([]string, 0) - for arg := range gctx.Args.Arguments[1:] { - ch, err := gctx.Session.Channel(dgoutils.Trimmer(gctx, arg)) + for _, arg := range gctx.Args.Arguments[1:] { + ch, err := gctx.Session.Channel(dgoutils.TrimmerRaw(arg.Raw)) if err != nil { return err } @@ -558,7 +558,7 @@ func addChannel(b *bot.Bot) func(*gumi.Ctx) error { channels := make([]string, 0) for _, arg := range gctx.Args.Arguments { - ch, err := gctx.Session.Channel(strings.Trim(arg.Raw, "<#>")) + ch, err := gctx.Session.Channel(dgoutils.TrimmerRaw(arg.Raw)) if err != nil { return err } @@ -643,7 +643,7 @@ func removeChannel(b *bot.Bot) func(*gumi.Ctx) error { channels := make([]string, 0) for _, arg := range gctx.Args.Arguments { - ch, err := gctx.Session.Channel(strings.Trim(arg.Raw, "<#>")) + ch, err := gctx.Session.Channel(dgoutils.TrimmerRaw(arg.Raw)) if err != nil { return messages.ErrChannelNotFound(err, arg.Raw) } diff --git a/commands/user.go b/commands/user.go index e3d30e8..7cca757 100644 --- a/commands/user.go +++ b/commands/user.go @@ -379,8 +379,8 @@ func push(b *bot.Bot) func(*gumi.Ctx) error { defer cancel() inserted := make([]string, 0, gctx.Args.Len()) - for arg := range gctx.Args.Arguments { - channelID := dgoutils.Trimmer(gctx, arg) + for _, arg := range gctx.Args.Arguments { + channelID := dgoutils.TrimmerRaw(arg.Raw) ch, err := gctx.Session.Channel(channelID) if err != nil { return messages.ErrChannelNotFound(err, channelID) diff --git a/internal/dgoutils/dgoutils.go b/internal/dgoutils/dgoutils.go index 6771aa5..34a3534 100644 --- a/internal/dgoutils/dgoutils.go +++ b/internal/dgoutils/dgoutils.go @@ -40,6 +40,11 @@ func Trimmer(gctx *gumi.Ctx, n int) string { return strings.Trim(gctx.Args.Get(n).Raw, "") } +// TrimmerRaw is the same as Trimmer but directly on a Raw string. +func TrimmerRaw(arg string) string { + return strings.Trim(arg, "") +} + // ExpireMessage deletes a specified message after a certain time func ExpireMessage(b *bot.Bot, s *discordgo.Session, msg *discordgo.Message) { go func() { diff --git a/post/post.go b/post/post.go index d03e201..25d393f 100644 --- a/post/post.go +++ b/post/post.go @@ -98,8 +98,8 @@ func (p *Post) Send(ctx context.Context) error { // Otherwise, don't crosspost at all. if p.ExcludeChannel { excludedChannels := make(map[string]struct{}) - for arg := range strings.Fields(p.Ctx.Args.Raw) { - id := dgoutils.Trimmer(p.Ctx, arg) + for _, arg := range strings.Fields(p.Ctx.Args.Raw) { + id := dgoutils.TrimmerRaw(arg) excludedChannels[id] = struct{}{} } From d560d4fadae38798a2213418f263878736b1b636 Mon Sep 17 00:00:00 2001 From: XangelMusic Date: Wed, 18 Sep 2024 04:03:19 +0800 Subject: [PATCH 15/30] refactor: Trimmer functions --- commands/settings.go | 8 ++++---- commands/user.go | 8 ++++---- internal/dgoutils/dgoutils.go | 5 +++++ post/post.go | 4 ++-- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/commands/settings.go b/commands/settings.go index 66ed533..ab7efee 100644 --- a/commands/settings.go +++ b/commands/settings.go @@ -492,8 +492,8 @@ func artChannels(b *bot.Bot) func(*gumi.Ctx) error { } channels := make([]string, 0) - for arg := range gctx.Args.Arguments[1:] { - ch, err := gctx.Session.Channel(dgoutils.Trimmer(gctx, arg)) + for _, arg := range gctx.Args.Arguments[1:] { + ch, err := gctx.Session.Channel(dgoutils.TrimmerRaw(arg.Raw)) if err != nil { return err } @@ -558,7 +558,7 @@ func addChannel(b *bot.Bot) func(*gumi.Ctx) error { channels := make([]string, 0) for _, arg := range gctx.Args.Arguments { - ch, err := gctx.Session.Channel(strings.Trim(arg.Raw, "<#>")) + ch, err := gctx.Session.Channel(dgoutils.TrimmerRaw(arg.Raw)) if err != nil { return err } @@ -643,7 +643,7 @@ func removeChannel(b *bot.Bot) func(*gumi.Ctx) error { channels := make([]string, 0) for _, arg := range gctx.Args.Arguments { - ch, err := gctx.Session.Channel(strings.Trim(arg.Raw, "<#>")) + ch, err := gctx.Session.Channel(dgoutils.TrimmerRaw(arg.Raw)) if err != nil { return messages.ErrChannelNotFound(err, arg.Raw) } diff --git a/commands/user.go b/commands/user.go index e3d30e8..0671c78 100644 --- a/commands/user.go +++ b/commands/user.go @@ -379,8 +379,8 @@ func push(b *bot.Bot) func(*gumi.Ctx) error { defer cancel() inserted := make([]string, 0, gctx.Args.Len()) - for arg := range gctx.Args.Arguments { - channelID := dgoutils.Trimmer(gctx, arg) + for _, arg := range gctx.Args.Arguments { + channelID := dgoutils.TrimmerRaw(arg.Raw) ch, err := gctx.Session.Channel(channelID) if err != nil { return messages.ErrChannelNotFound(err, channelID) @@ -450,8 +450,8 @@ func remove(b *bot.Bot) func(*gumi.Ctx) error { defer cancel() removed := make([]string, 0, gctx.Args.Len()) - for arg := range gctx.Args.Arguments { - channelID := dgoutils.Trimmer(gctx, arg) + for _, arg := range gctx.Args.Arguments { + channelID := dgoutils.TrimmerRaw(arg.Raw) if !slices.Contains(group.Children, channelID) { continue diff --git a/internal/dgoutils/dgoutils.go b/internal/dgoutils/dgoutils.go index 6771aa5..34a3534 100644 --- a/internal/dgoutils/dgoutils.go +++ b/internal/dgoutils/dgoutils.go @@ -40,6 +40,11 @@ func Trimmer(gctx *gumi.Ctx, n int) string { return strings.Trim(gctx.Args.Get(n).Raw, "") } +// TrimmerRaw is the same as Trimmer but directly on a Raw string. +func TrimmerRaw(arg string) string { + return strings.Trim(arg, "") +} + // ExpireMessage deletes a specified message after a certain time func ExpireMessage(b *bot.Bot, s *discordgo.Session, msg *discordgo.Message) { go func() { diff --git a/post/post.go b/post/post.go index d03e201..25d393f 100644 --- a/post/post.go +++ b/post/post.go @@ -98,8 +98,8 @@ func (p *Post) Send(ctx context.Context) error { // Otherwise, don't crosspost at all. if p.ExcludeChannel { excludedChannels := make(map[string]struct{}) - for arg := range strings.Fields(p.Ctx.Args.Raw) { - id := dgoutils.Trimmer(p.Ctx, arg) + for _, arg := range strings.Fields(p.Ctx.Args.Raw) { + id := dgoutils.TrimmerRaw(arg) excludedChannels[id] = struct{}{} } From 8164a2ad3fcccf29073a3f42215f3ccfefff751d Mon Sep 17 00:00:00 2001 From: XangelMusic Date: Wed, 18 Sep 2024 04:06:41 +0800 Subject: [PATCH 16/30] boost: added OnChannelDelete and manual deletion of missing Art Channels --- commands/settings.go | 7 ++++++- handlers/handlers.go | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/commands/settings.go b/commands/settings.go index ab7efee..03357b3 100644 --- a/commands/settings.go +++ b/commands/settings.go @@ -645,7 +645,12 @@ func removeChannel(b *bot.Bot) func(*gumi.Ctx) error { for _, arg := range gctx.Args.Arguments { ch, err := gctx.Session.Channel(dgoutils.TrimmerRaw(arg.Raw)) if err != nil { - return messages.ErrChannelNotFound(err, arg.Raw) + if !strings.Contains(err.Error(), "404") { + return messages.ErrChannelNotFound(err, arg.Raw) + } + + channels = append(channels, dgoutils.TrimmerRaw(arg.Raw)) + continue } if ch.GuildID != gctx.Event.GuildID { diff --git a/handlers/handlers.go b/handlers/handlers.go index aafa2b1..d0c93a3 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -30,6 +30,7 @@ func RegisterHandlers(b *bot.Bot) { b.AddHandler(OnGuildCreate(b)) b.AddHandler(OnGuildDelete(b)) b.AddHandler(OnGuildBanAdd(b)) + b.AddHandler(OnChannelDelete(b)) b.AddHandler(OnReactionAdd(b)) b.AddHandler(OnReactionRemove(b)) b.AddHandler(OnMessageRemove(b)) @@ -134,6 +135,27 @@ func OnGuildBanAdd(b *bot.Bot) func(*discordgo.Session, *discordgo.GuildBanAdd) } } +func OnChannelDelete(b *bot.Bot) func(*discordgo.Session, *discordgo.ChannelDelete) { + return func(s *discordgo.Session, ch *discordgo.ChannelDelete) { + guild, err := b.Store.Guild(b.Context, ch.GuildID) + if err != nil { + return + } + + if len(guild.ArtChannels) == 0 { + return + } + + if slices.Contains(guild.ArtChannels, ch.ID) { + _, err = b.Store.DeleteArtChannels( + b.Context, + guild.ID, + []string{ch.ID}, + ) + } + } +} + func OnMessageRemove(b *bot.Bot) func(*discordgo.Session, *discordgo.MessageDelete) { return func(s *discordgo.Session, m *discordgo.MessageDelete) { log := b.Log.With("channel_id", m.ChannelID, "parent_id", m.ID) From ff00199b00b84518bb917b7732154c2db645658f Mon Sep 17 00:00:00 2001 From: XangelMusic Date: Wed, 18 Sep 2024 04:06:41 +0800 Subject: [PATCH 17/30] boost: added OnChannelDelete and manual deletion of missing Art Channels --- commands/settings.go | 7 ++++++- handlers/handlers.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/commands/settings.go b/commands/settings.go index ab7efee..03357b3 100644 --- a/commands/settings.go +++ b/commands/settings.go @@ -645,7 +645,12 @@ func removeChannel(b *bot.Bot) func(*gumi.Ctx) error { for _, arg := range gctx.Args.Arguments { ch, err := gctx.Session.Channel(dgoutils.TrimmerRaw(arg.Raw)) if err != nil { - return messages.ErrChannelNotFound(err, arg.Raw) + if !strings.Contains(err.Error(), "404") { + return messages.ErrChannelNotFound(err, arg.Raw) + } + + channels = append(channels, dgoutils.TrimmerRaw(arg.Raw)) + continue } if ch.GuildID != gctx.Event.GuildID { diff --git a/handlers/handlers.go b/handlers/handlers.go index aafa2b1..4c0d3be 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -30,6 +30,7 @@ func RegisterHandlers(b *bot.Bot) { b.AddHandler(OnGuildCreate(b)) b.AddHandler(OnGuildDelete(b)) b.AddHandler(OnGuildBanAdd(b)) + b.AddHandler(OnChannelDelete(b)) b.AddHandler(OnReactionAdd(b)) b.AddHandler(OnReactionRemove(b)) b.AddHandler(OnMessageRemove(b)) @@ -134,6 +135,34 @@ func OnGuildBanAdd(b *bot.Bot) func(*discordgo.Session, *discordgo.GuildBanAdd) } } +func OnChannelDelete(b *bot.Bot) func(*discordgo.Session, *discordgo.ChannelDelete) { + return func(s *discordgo.Session, ch *discordgo.ChannelDelete) { + log := b.Log.With("channel_id", ch.ID, "guild_id", ch.GuildID) + + guild, err := b.Store.Guild(b.Context, ch.GuildID) + if err != nil { + log.With("error", err).Warn("failed to find guild") + return + } + + if len(guild.ArtChannels) == 0 { + return + } + + if slices.Contains(guild.ArtChannels, ch.ID) { + _, err = b.Store.DeleteArtChannels( + b.Context, + guild.ID, + []string{ch.ID}, + ) + + if err != nil { + log.With("error", err).Warn("failed to delete art channel") + } + } + } +} + func OnMessageRemove(b *bot.Bot) func(*discordgo.Session, *discordgo.MessageDelete) { return func(s *discordgo.Session, m *discordgo.MessageDelete) { log := b.Log.With("channel_id", m.ChannelID, "parent_id", m.ID) From 8d47ab4d71885dc6edbb4f7ce718a893cf2e6ace Mon Sep 17 00:00:00 2001 From: XangelMusic <22012301+XangelMusic@users.noreply.github.com> Date: Thu, 19 Sep 2024 01:20:43 +0800 Subject: [PATCH 18/30] Update handlers.go --- handlers/handlers.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/handlers/handlers.go b/handlers/handlers.go index d0c93a3..4c0d3be 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -137,8 +137,11 @@ func OnGuildBanAdd(b *bot.Bot) func(*discordgo.Session, *discordgo.GuildBanAdd) func OnChannelDelete(b *bot.Bot) func(*discordgo.Session, *discordgo.ChannelDelete) { return func(s *discordgo.Session, ch *discordgo.ChannelDelete) { + log := b.Log.With("channel_id", ch.ID, "guild_id", ch.GuildID) + guild, err := b.Store.Guild(b.Context, ch.GuildID) if err != nil { + log.With("error", err).Warn("failed to find guild") return } @@ -152,6 +155,10 @@ func OnChannelDelete(b *bot.Bot) func(*discordgo.Session, *discordgo.ChannelDele guild.ID, []string{ch.ID}, ) + + if err != nil { + log.With("error", err).Warn("failed to delete art channel") + } } } } From 7ba47228b3827cd2bc584d976f65945b15b53d8d Mon Sep 17 00:00:00 2001 From: XangelMusic Date: Thu, 19 Sep 2024 03:39:21 +0800 Subject: [PATCH 19/30] refactor: cleanup RepostDetector code in fetch() --- post/post.go | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/post/post.go b/post/post.go index 25d393f..a73b542 100644 --- a/post/post.go +++ b/post/post.go @@ -281,22 +281,22 @@ func (p *Post) fetch(ctx context.Context, guild *store.Guild, channelID string) isRepost = true } - } - if guild.Repost != store.GuildRepostDisabled && !isRepost { - err := p.Bot.RepostDetector.Create( - gctx, - &repost.Repost{ - ID: id, - URL: url, - GuildID: guild.ID, - ChannelID: channelID, - MessageID: p.Ctx.Event.ID, - }, - guild.RepostExpiration, - ) - if err != nil { - log.With("error", err).Error("error creating a repost") + if !isRepost { + err := p.Bot.RepostDetector.Create( + gctx, + &repost.Repost{ + ID: id, + URL: url, + GuildID: guild.ID, + ChannelID: channelID, + MessageID: p.Ctx.Event.ID, + }, + guild.RepostExpiration, + ) + if err != nil { + log.With("error", err).Error("error creating a repost") + } } } From 180e41a912c2ea4058e98a5923a931602c47decb Mon Sep 17 00:00:00 2001 From: XangelMusic Date: Thu, 19 Sep 2024 03:39:21 +0800 Subject: [PATCH 20/30] refactor: cleanup RepostDetector code in fetch() --- post/post.go | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/post/post.go b/post/post.go index 25d393f..cd1f83f 100644 --- a/post/post.go +++ b/post/post.go @@ -266,7 +266,6 @@ func (p *Post) fetch(ctx context.Context, guild *store.Guild, channelID string) ) log.Debug("matched a url") - var isRepost bool if guild.Repost != store.GuildRepostDisabled { rep, err := p.Bot.RepostDetector.Find(gctx, channelID, id) if err != nil && !errors.Is(err, repost.ErrNotFound) { @@ -278,25 +277,21 @@ func (p *Post) fetch(ctx context.Context, guild *store.Guild, channelID string) if p.CrosspostMode || guild.Repost == store.GuildRepostStrict { return nil } - - isRepost = true - } - } - - if guild.Repost != store.GuildRepostDisabled && !isRepost { - err := p.Bot.RepostDetector.Create( - gctx, - &repost.Repost{ - ID: id, - URL: url, - GuildID: guild.ID, - ChannelID: channelID, - MessageID: p.Ctx.Event.ID, - }, - guild.RepostExpiration, - ) - if err != nil { - log.With("error", err).Error("error creating a repost") + } else { + err := p.Bot.RepostDetector.Create( + gctx, + &repost.Repost{ + ID: id, + URL: url, + GuildID: guild.ID, + ChannelID: channelID, + MessageID: p.Ctx.Event.ID, + }, + guild.RepostExpiration, + ) + if err != nil { + log.With("error", err).Error("error creating a repost") + } } } From a27e17a1262ecce19f6d76e287f106c8028c5902 Mon Sep 17 00:00:00 2001 From: XangelMusic Date: Thu, 19 Sep 2024 11:59:06 +0800 Subject: [PATCH 21/30] refactor: Repost message appears last --- post/post.go | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/post/post.go b/post/post.go index cd1f83f..2af9bd6 100644 --- a/post/post.go +++ b/post/post.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "github.com/VTGare/embeds" "reflect" "slices" "strconv" @@ -19,7 +20,6 @@ import ( "github.com/VTGare/boe-tea-go/messages" "github.com/VTGare/boe-tea-go/repost" "github.com/VTGare/boe-tea-go/store" - "github.com/VTGare/embeds" "github.com/VTGare/gumi" "github.com/bwmarrin/discordgo" "golang.org/x/sync/errgroup" @@ -83,9 +83,7 @@ func (p *Post) Send(ctx context.Context) error { return fmt.Errorf("failed to fetch artworks: %w", err) } - p.handleReposts(guild, res) - - sent, err := p.sendMessages(guild, p.Ctx.Event.ChannelID, res.Artworks) + sent, err := p.sendMessages(guild, p.Ctx.Event.ChannelID, res) if err != nil { return err } @@ -93,6 +91,8 @@ func (p *Post) Send(ctx context.Context) error { allSent := make([]*cache.MessageInfo, 0) allSent = append(allSent, sent...) + p.handleReposts(guild, res) + if group, ok := user.FindGroup(p.Ctx.Event.ChannelID); user.Crosspost && ok { // If channels were successfully excluded, crosspost to trimmed channels. // Otherwise, don't crosspost at all. @@ -203,7 +203,7 @@ func (p *Post) Crosspost(ctx context.Context, userID string, group *store.Group) return } - sent, err := p.sendMessages(guild, channelID, res.Artworks) + sent, err := p.sendMessages(guild, channelID, res) if err != nil { log.With("error", err).Error("failed to send messages") return @@ -365,14 +365,14 @@ func (p *Post) fetch(ctx context.Context, guild *store.Guild, channelID string) return res, nil } -func (p *Post) handleReposts(guild *store.Guild, res *fetchResult) error { +func (p *Post) handleReposts(guild *store.Guild, res *fetchResult) { log := p.Bot.Log.With( "guild_id", guild.ID, "user_id", p.Ctx.Event.Author.ID, ) if len(res.Reposts) == 0 { - return nil + return } if guild.Repost == store.GuildRepostStrict { @@ -392,8 +392,7 @@ func (p *Post) handleReposts(guild *store.Guild, res *fetchResult) error { messageID = p.Ctx.Event.ID ) - err := p.Ctx.Session.ChannelMessageDelete(channelID, messageID) - if err != nil { + if err = p.Ctx.Session.ChannelMessageDelete(channelID, messageID); err != nil { log.With( "channel_id", channelID, "message_id", messageID, @@ -421,22 +420,21 @@ func (p *Post) handleReposts(guild *store.Guild, res *fetchResult) error { ) } - msg, err := p.Ctx.Session.ChannelMessageSendEmbed(p.Ctx.Event.ChannelID, eb.Finalize()) + repostMessage, err := p.Ctx.Session.ChannelMessageSendEmbed(p.Ctx.Event.ChannelID, eb.Finalize()) if err != nil { - return fmt.Errorf("failed to send message to discord: %w", err) + log.With("error", err).Warn("failed to send repost message") } - dgoutils.ExpireMessage(p.Bot, p.Ctx.Session, msg) - return nil + dgoutils.ExpireMessage(p.Bot, p.Ctx.Session, repostMessage) } -func (p *Post) sendMessages(guild *store.Guild, channelID string, artworks []artworks.Artwork) ([]*cache.MessageInfo, error) { +func (p *Post) sendMessages(guild *store.Guild, channelID string, res *fetchResult) ([]*cache.MessageInfo, error) { sent := make([]*cache.MessageInfo, 0) - if len(artworks) == 0 { + if len(res.Artworks) == 0 { return sent, nil } - allMessages, err := p.generateMessages(guild, artworks) + allMessages, err := p.generateMessages(guild, res.Artworks) if err != nil { return nil, err } @@ -446,7 +444,7 @@ func (p *Post) sendMessages(guild *store.Guild, channelID string, artworks []art } mediaCount := 0 - for _, artwork := range artworks { + for _, artwork := range res.Artworks { mediaCount += artwork.Len() } From 98e5f75a34307f94441069129b4dd0b91bbe4905 Mon Sep 17 00:00:00 2001 From: XangelMusic Date: Tue, 24 Sep 2024 06:24:03 +0800 Subject: [PATCH 22/30] boost: Repost Detector won't appear for deleted posts --- artworks/artstation/artstation.go | 6 +++++ artworks/artworks.go | 1 + artworks/deviant/deviant.go | 6 +++++ artworks/pixiv/pixiv.go | 4 +++ artworks/twitter/twitter.go | 4 +++ handlers/handlers.go | 20 +++++++++----- internal/cache/cache.go | 7 ++--- post/post.go | 8 +++--- repost/memory.go | 9 +++++++ repost/redis.go | 43 ++++++++++++++++++++++++++----- repost/repost.go | 3 ++- 11 files changed, 90 insertions(+), 21 deletions(-) diff --git a/artworks/artstation/artstation.go b/artworks/artstation/artstation.go index dac53fa..fd4de33 100644 --- a/artworks/artstation/artstation.go +++ b/artworks/artstation/artstation.go @@ -41,6 +41,7 @@ type ArtstationResponse struct { HideAsAdult bool `json:"hide_as_adult,omitempty"` VisibleOnArtstation bool `json:"visible_on_artstation,omitempty"` + artworkID string AIGenerated bool CreatedAt time.Time `json:"created_at,omitempty"` } @@ -93,6 +94,7 @@ func (as *Artstation) Find(id string) (artworks.Artwork, error) { return nil, err } + res.artworkID = id res.AIGenerated = artworks.IsAIGenerated(res.Tags...) return res, nil @@ -162,6 +164,10 @@ func (artwork *ArtstationResponse) MessageSends(footer string, tagsEnabled bool) return eb.ToEmbed(), nil } +func (artwork *ArtstationResponse) ArtworkID() string { + return artwork.artworkID +} + func (artwork *ArtstationResponse) URL() string { return artwork.Permalink } diff --git a/artworks/artworks.go b/artworks/artworks.go index 37516c5..1d5a47b 100644 --- a/artworks/artworks.go +++ b/artworks/artworks.go @@ -15,6 +15,7 @@ type Provider interface { type Artwork interface { StoreArtwork() *store.Artwork MessageSends(footer string, tags bool) ([]*discordgo.MessageSend, error) + ArtworkID() string URL() string Len() int } diff --git a/artworks/deviant/deviant.go b/artworks/deviant/deviant.go index 9d7c37d..1923202 100644 --- a/artworks/deviant/deviant.go +++ b/artworks/deviant/deviant.go @@ -32,6 +32,7 @@ type Artwork struct { Comments int AIGenerated bool CreatedAt time.Time + artworkID string url string } @@ -96,6 +97,7 @@ func (d *DeviantArt) Find(id string) (artworks.Artwork, error) { Favorites: res.Community.Statistics.Attributes.Favorites, Comments: res.Community.Statistics.Attributes.Comments, CreatedAt: res.Pubdate, + artworkID: id, url: res.AuthorURL + "/art/" + id, } @@ -152,6 +154,10 @@ func (a *Artwork) StoreArtwork() *store.Artwork { } } +func (a *Artwork) ArtworkID() string { + return a.artworkID +} + func (a *Artwork) URL() string { return a.url } diff --git a/artworks/pixiv/pixiv.go b/artworks/pixiv/pixiv.go index 5f27c83..44354c5 100644 --- a/artworks/pixiv/pixiv.go +++ b/artworks/pixiv/pixiv.go @@ -195,6 +195,10 @@ func (a *Artwork) MessageSends(footer string, tagsEnabled bool) ([]*discordgo.Me return eb.ToEmbed(), nil } +func (a *Artwork) ArtworkID() string { + return a.ID +} + func (a *Artwork) URL() string { return a.url } diff --git a/artworks/twitter/twitter.go b/artworks/twitter/twitter.go index 8a55bda..8979ea7 100644 --- a/artworks/twitter/twitter.go +++ b/artworks/twitter/twitter.go @@ -180,6 +180,10 @@ func downloadVideo(fileURL string) (*discordgo.File, error) { }, nil } +func (a *Artwork) ArtworkID() string { + return a.ID +} + func (a *Artwork) URL() string { return a.Permalink } diff --git a/handlers/handlers.go b/handlers/handlers.go index 4c0d3be..d5978ee 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -167,8 +167,7 @@ func OnMessageRemove(b *bot.Bot) func(*discordgo.Session, *discordgo.MessageDele return func(s *discordgo.Session, m *discordgo.MessageDelete) { log := b.Log.With("channel_id", m.ChannelID, "parent_id", m.ID) msg, ok := b.EmbedCache.Get( - m.ChannelID, - m.ID, + m.ChannelID, m.ID, ) if !ok { @@ -179,18 +178,27 @@ func OnMessageRemove(b *bot.Bot) func(*discordgo.Session, *discordgo.MessageDele m.ChannelID, m.ID, ) - if msg.Parent { + if msg.IsParent { log.With("user_id", msg.AuthorID).Info("removing children messages") for _, child := range msg.Children { + log.With("user_id", msg.AuthorID, "message_id", child.MessageID).Info("removing a respost") + + if err := b.RepostDetector.Delete(b.Context, child.ChannelID, child.ArtworkID); err != nil { + if strings.Contains(err.Error(), "repost not found") { + log.With("error", err) + } + + log.With("error", err).Warn("failed to remove repost") + } + log.With("user_id", msg.AuthorID, "message_id", child.MessageID).Info("removing a child message") b.EmbedCache.Remove( child.ChannelID, child.MessageID, ) - err := s.ChannelMessageDelete(child.ChannelID, child.MessageID) - if err != nil { + if err := s.ChannelMessageDelete(child.ChannelID, child.MessageID); err != nil { log.With("error", err, "message_id", child.MessageID).Warn("failed to delete child message") } } @@ -233,7 +241,7 @@ func OnReactionAdd(b *bot.Bot) func(*discordgo.Session, *discordgo.MessageReacti return err } - if !msg.Parent { + if !msg.IsParent { return nil } diff --git a/internal/cache/cache.go b/internal/cache/cache.go index 8153715..3cf8007 100644 --- a/internal/cache/cache.go +++ b/internal/cache/cache.go @@ -69,6 +69,7 @@ type EmbedCache struct { type MessageInfo struct { MessageID string ChannelID string + ArtworkID string } // CachedEmbed stores information about an embed that's later retrieved in @@ -78,7 +79,7 @@ type MessageInfo struct { // all embeds sent by Boe Tea by posting the message, including crossposted messages. type CachedPost struct { AuthorID string - Parent bool + IsParent bool Children []*MessageInfo } @@ -104,14 +105,14 @@ func (ec *EmbedCache) Get(channelID, messageID string) (*CachedPost, bool) { return nil, false } -func (ec *EmbedCache) Set(userID, channelID, messageID string, parent bool, children ...*MessageInfo) { +func (ec *EmbedCache) Set(userID, channelID, messageID string, isParent bool, children ...*MessageInfo) { key := ec.makeKey( channelID, messageID, ) ec.cache.Set(key, &CachedPost{ AuthorID: userID, - Parent: parent, + IsParent: isParent, Children: children, }) } diff --git a/post/post.go b/post/post.go index 2af9bd6..8d7a645 100644 --- a/post/post.go +++ b/post/post.go @@ -450,7 +450,7 @@ func (p *Post) sendMessages(guild *store.Guild, channelID string, res *fetchResu // It only happens from commands so only first artwork should be affected. allMessages[0] = p.skipArtworks(allMessages[0]) - sendMessage := func(message *discordgo.MessageSend) error { + sendMessage := func(message *discordgo.MessageSend, artworkID string) error { s := p.Ctx.Session if p.CrosspostMode { guildID, err := strconv.ParseInt(guild.ID, 10, 64) @@ -466,7 +466,7 @@ func (p *Post) sendMessages(guild *store.Guild, channelID string, res *fetchResu return fmt.Errorf("failed to send message: %w", err) } - sent = append(sent, &cache.MessageInfo{MessageID: msg.ID, ChannelID: msg.ChannelID}) + sent = append(sent, &cache.MessageInfo{MessageID: msg.ID, ChannelID: msg.ChannelID, ArtworkID: artworkID}) // If URL isn't set then it's an error embed. // If media count equals 0, it's most likely a Tweet without images and can't be bookmarked. @@ -494,8 +494,8 @@ func (p *Post) sendMessages(guild *store.Guild, channelID string, res *fetchResu ) for _, messages := range allMessages { - for _, message := range messages { - err := sendMessage(message) + for i, message := range messages { + err := sendMessage(message, res.Artworks[i].ArtworkID()) if err != nil { log.With(err).Warn("failed to send artwork message") } diff --git a/repost/memory.go b/repost/memory.go index b497125..b8d9b4b 100644 --- a/repost/memory.go +++ b/repost/memory.go @@ -16,6 +16,15 @@ func NewMemory() Detector { return &inMemory{cache: ttlcache.NewCache()} } +func (rd inMemory) Delete(_ context.Context, channelID, artworkID string) error { + ok := rd.cache.Remove(fmt.Sprintf("%v:%v", channelID, artworkID)) + if !ok { + return ErrNotFound + } + + return nil +} + func (rd inMemory) Create(_ context.Context, rep *Repost, ttl time.Duration) error { rep.ExpiresAt = time.Now().Add(ttl) rd.cache.SetWithTTL(rd.key(rep), rep, ttl) diff --git a/repost/redis.go b/repost/redis.go index 3fcf690..ff2f711 100644 --- a/repost/redis.go +++ b/repost/redis.go @@ -26,6 +26,19 @@ func NewRedis(addr string) (Detector, error) { return &redisDetector{client}, nil } +func (rd redisDetector) exists(ctx context.Context, key string) error { + exists, err := rd.client.Exists(ctx, key).Result() + if err != nil { + return err + } + + if exists == 0 { + return ErrNotFound + } + + return nil +} + func (rd redisDetector) Find(ctx context.Context, channelID, artworkID string) (*Repost, error) { var ( rep Repost @@ -33,16 +46,11 @@ func (rd redisDetector) Find(ctx context.Context, channelID, artworkID string) ( ttl time.Duration ) - exists, err := rd.client.Exists(ctx, key).Result() - if err != nil { + if err := rd.exists(ctx, key); err != nil { return nil, err } - if exists == 0 { - return nil, ErrNotFound - } - - _, err = rd.client.Pipelined(ctx, func(pipe redis.Pipeliner) error { + _, err := rd.client.Pipelined(ctx, func(pipe redis.Pipeliner) error { err := rd.client.HGetAll(ctx, key).Scan(&rep) if err != nil { return err @@ -89,6 +97,27 @@ func (rd redisDetector) Create(ctx context.Context, repost *Repost, duration tim return nil } +func (rd redisDetector) Delete(ctx context.Context, channelID, artworkID string) error { + key := fmt.Sprintf("channel:%v:artwork:%v", channelID, artworkID) + + if err := rd.exists(ctx, key); err != nil { + return err + } + + _, err := rd.client.Pipelined(ctx, func(pipe redis.Pipeliner) error { + if _, err := rd.client.Del(ctx, key).Result(); err != nil { + return err + } + + return nil + }) + if err != nil { + return err + } + + return nil +} + func (rd redisDetector) Close() error { return rd.client.Close() } diff --git a/repost/repost.go b/repost/repost.go index a650919..850ac63 100644 --- a/repost/repost.go +++ b/repost/repost.go @@ -10,7 +10,8 @@ var ErrNotFound = errors.New("repost not found") type Detector interface { Find(ctx context.Context, channelID string, artworkID string) (*Repost, error) - Create(context.Context, *Repost, time.Duration) error + Create(ctx context.Context, repost *Repost, duration time.Duration) error + Delete(ctx context.Context, channelID string, artworkID string) error Close() error } From ca45fe28908e0dbfc64b4909dce2549658d40d7e Mon Sep 17 00:00:00 2001 From: XangelMusic <22012301+XangelMusic@users.noreply.github.com> Date: Mon, 14 Oct 2024 02:37:34 +0800 Subject: [PATCH 23/30] Update post.go --- post/post.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/post/post.go b/post/post.go index 8d7a645..91791b2 100644 --- a/post/post.go +++ b/post/post.go @@ -493,8 +493,8 @@ func (p *Post) sendMessages(guild *store.Guild, channelID string, res *fetchResu "crosspost", p.CrosspostMode, ) - for _, messages := range allMessages { - for i, message := range messages { + for i, messages := range allMessages { + for _, message := range messages { err := sendMessage(message, res.Artworks[i].ArtworkID()) if err != nil { log.With(err).Warn("failed to send artwork message") From e155fd3ba6be03a493150e1f67044feee5bd3cd5 Mon Sep 17 00:00:00 2001 From: XangelMusic Date: Mon, 14 Oct 2024 14:07:54 +0800 Subject: [PATCH 24/30] fix: Repost Detector delete messages --- handlers/handlers.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/handlers/handlers.go b/handlers/handlers.go index d5978ee..6c0d44f 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -187,9 +187,9 @@ func OnMessageRemove(b *bot.Bot) func(*discordgo.Session, *discordgo.MessageDele if err := b.RepostDetector.Delete(b.Context, child.ChannelID, child.ArtworkID); err != nil { if strings.Contains(err.Error(), "repost not found") { log.With("error", err) + } else { + log.With("error", err).Warn("failed to remove repost") } - - log.With("error", err).Warn("failed to remove repost") } log.With("user_id", msg.AuthorID, "message_id", child.MessageID).Info("removing a child message") From 6b6079dc88420a34ecac4c8ee7c79aa9f1d19cf6 Mon Sep 17 00:00:00 2001 From: VTGare Date: Sun, 17 Nov 2024 17:26:53 +0200 Subject: [PATCH 25/30] revert artworks --- artworks/artstation/artstation.go | 108 +++++---- artworks/artstation/artstation_suite_test.go | 4 +- artworks/artworks.go | 49 ++++- artworks/deviant/deviant.go | 126 ++++++----- artworks/embed/embed.go | 93 -------- artworks/error.go | 38 ---- artworks/pixiv/pixiv.go | 220 +++++++++++-------- artworks/pixiv/pixiv_suite_test.go | 2 +- artworks/twitter/fxtwitter.go | 16 +- artworks/twitter/matcher.go | 9 +- artworks/twitter/twitter.go | 126 ++++++----- artworks/twitter/twitter_suite_test.go | 6 +- 12 files changed, 404 insertions(+), 393 deletions(-) delete mode 100644 artworks/embed/embed.go delete mode 100644 artworks/error.go diff --git a/artworks/artstation/artstation.go b/artworks/artstation/artstation.go index fd4de33..33d816e 100644 --- a/artworks/artstation/artstation.go +++ b/artworks/artstation/artstation.go @@ -3,7 +3,6 @@ package artstation import ( "encoding/json" "fmt" - "github.com/VTGare/boe-tea-go/artworks/embed" "net/http" "regexp" "strconv" @@ -41,7 +40,6 @@ type ArtstationResponse struct { HideAsAdult bool `json:"hide_as_adult,omitempty"` VisibleOnArtstation bool `json:"visible_on_artstation,omitempty"` - artworkID string AIGenerated bool CreatedAt time.Time `json:"created_at,omitempty"` } @@ -73,32 +71,40 @@ type Category struct { } func New() artworks.Provider { + r := regexp.MustCompile(`(?i)https:\/\/(?:www\.)?artstation\.com\/artwork\/([\w\-]+)`) + return &Artstation{ - regex: regexp.MustCompile(`(?i)https://(?:www\.)?artstation\.com/artwork/([\w\-]+)`), + regex: r, } } func (as *Artstation) Find(id string) (artworks.Artwork, error) { - return artworks.NewError(as, func() (artworks.Artwork, error) { - reqURL := fmt.Sprintf("https://www.artstation.com/projects/%v.json", id) - resp, err := http.Get(reqURL) - if err != nil { - return nil, err - } + artwork, err := as._find(id) + if err != nil { + return nil, artworks.NewError(as, err) + } - defer resp.Body.Close() + return artwork, nil +} - res := &ArtstationResponse{} - err = json.NewDecoder(resp.Body).Decode(res) - if err != nil { - return nil, err - } +func (as *Artstation) _find(id string) (artworks.Artwork, error) { + reqURL := fmt.Sprintf("https://www.artstation.com/projects/%v.json", id) + resp, err := http.Get(reqURL) + if err != nil { + return nil, err + } + + defer resp.Body.Close() - res.artworkID = id - res.AIGenerated = artworks.IsAIGenerated(res.Tags...) + res := &ArtstationResponse{} + err = json.NewDecoder(resp.Body).Decode(res) + if err != nil { + return nil, err + } - return res, nil - }) + res.AIGenerated = artworks.IsAIGenerated(res.Tags...) + + return res, nil } func (as *Artstation) Match(url string) (string, bool) { @@ -129,8 +135,13 @@ func (artwork *ArtstationResponse) StoreArtwork() *store.Artwork { } func (artwork *ArtstationResponse) MessageSends(footer string, tagsEnabled bool) ([]*discordgo.MessageSend, error) { - if len(artwork.Assets) == 0 { - eb := embeds.NewBuilder() + var ( + length = len(artwork.Assets) + pages = make([]*discordgo.MessageSend, 0, length) + eb = embeds.NewBuilder() + ) + + if length == 0 { eb.Title("❎ An error has occured.") eb.Description("Artwork has been deleted or the ID does not exist.") eb.Footer(footer, "") @@ -140,32 +151,51 @@ func (artwork *ArtstationResponse) MessageSends(footer string, tagsEnabled bool) }, nil } - eb := &embed.Embed{ - Title: artwork.Title, - Username: artwork.User.Name, - FieldName1: "Likes", - FieldValue1: strconv.Itoa(artwork.LikesCount), - FieldName2: "Views", - FieldValue2: []string{strconv.Itoa(artwork.ViewsCount)}, - URL: artwork.Permalink, - Timestamp: artwork.CreatedAt, - Footer: footer, - AIGenerated: artwork.AIGenerated, + if length > 1 { + eb.Title(fmt.Sprintf("%v by %v | Page %v / %v", artwork.Title, artwork.User.Name, 1, length)) + } else { + eb.Title(fmt.Sprintf("%v by %v", artwork.Title, artwork.User.Name)) } if tagsEnabled { - eb.Tags = bluemonday.StrictPolicy().Sanitize(artwork.Description) + desc := bluemonday.StrictPolicy().Sanitize(artwork.Description) + eb.Description(artworks.EscapeMarkdown(desc)) } - for _, image := range artwork.Assets { - eb.Images = append(eb.Images, image.ImageURL) + eb.URL(artwork.URL()). + AddField("Likes", strconv.Itoa(artwork.LikesCount), true). + AddField("Views", strconv.Itoa(artwork.ViewsCount), true). + Timestamp(artwork.CreatedAt) + + if footer != "" { + eb.Footer(footer, "") } - return eb.ToEmbed(), nil -} + if artwork.AIGenerated { + eb.AddField("⚠️ Disclaimer", "This artwork is AI-generated.") + } + + eb.Image(artwork.Assets[0].ImageURL) + pages = append(pages, &discordgo.MessageSend{Embeds: []*discordgo.MessageEmbed{eb.Finalize()}}) + if length > 1 { + for ind, image := range artwork.Assets[1:] { + eb := embeds.NewBuilder() + + eb.Title(fmt.Sprintf("%v by %v | Page %v / %v", artwork.Title, artwork.User.Name, ind+2, length)). + Image(image.ImageURL). + URL(artwork.URL()). + Timestamp(artwork.CreatedAt) + + if footer != "" { + eb.Footer(footer, "") + } + + eb.AddField("Likes", strconv.Itoa(artwork.LikesCount), true) + pages = append(pages, &discordgo.MessageSend{Embeds: []*discordgo.MessageEmbed{eb.Finalize()}}) + } + } -func (artwork *ArtstationResponse) ArtworkID() string { - return artwork.artworkID + return pages, nil } func (artwork *ArtstationResponse) URL() string { diff --git a/artworks/artstation/artstation_suite_test.go b/artworks/artstation/artstation_suite_test.go index 62006cb..7e3d46c 100644 --- a/artworks/artstation/artstation_suite_test.go +++ b/artworks/artstation/artstation_suite_test.go @@ -16,9 +16,9 @@ func TestArtstation(t *testing.T) { var _ = DescribeTable( "Match Artstation URL", func(url string, expectedID string, expectedResult bool) { - provider := artstation.New() + as := artstation.New() - id, ok := provider.Match(url) + id, ok := as.Match(url) Expect(id).To(BeEquivalentTo(expectedID)) Expect(ok).To(BeEquivalentTo(expectedResult)) }, diff --git a/artworks/artworks.go b/artworks/artworks.go index 1d5a47b..c5273af 100644 --- a/artworks/artworks.go +++ b/artworks/artworks.go @@ -1,9 +1,13 @@ package artworks import ( + "errors" + "fmt" + "regexp" + "strings" + "github.com/VTGare/boe-tea-go/store" "github.com/bwmarrin/discordgo" - "strings" ) type Provider interface { @@ -15,12 +19,49 @@ type Provider interface { type Artwork interface { StoreArtwork() *store.Artwork MessageSends(footer string, tags bool) ([]*discordgo.MessageSend, error) - ArtworkID() string URL() string Len() int } -func IsAIGenerated(content ...string) bool { +type Error struct { + provider string + cause error +} + +func (e *Error) Error() string { + return fmt.Sprintf("provider %v returned an error: %v", e.provider, e.cause.Error()) +} + +func (e *Error) Unwrap() error { + return e.cause +} + +func NewError(p Provider, err error) error { + return &Error{ + provider: fmt.Sprintf("%T", p), + cause: err, + } +} + +// Common errors +var ( + ErrArtworkNotFound = errors.New("artwork not found") + ErrRateLimited = errors.New("provider rate limited") +) + +func EscapeMarkdown(content string) string { + contents := strings.Split(content, "\n") + regex := regexp.MustCompile("^#{1,3}") + + for i, line := range contents { + if regex.MatchString(line) { + contents[i] = "\\" + line + } + } + return strings.Join(contents, "\n") +} + +func IsAIGenerated(contents ...string) bool { aiTags := []string{ "aiart", "aigenerated", @@ -32,7 +73,7 @@ func IsAIGenerated(content ...string) bool { "stablediffusion", } - for _, tag := range content { + for _, tag := range contents { for _, test := range aiTags { if strings.EqualFold(tag, test) { return true diff --git a/artworks/deviant/deviant.go b/artworks/deviant/deviant.go index 1923202..87f027d 100644 --- a/artworks/deviant/deviant.go +++ b/artworks/deviant/deviant.go @@ -2,6 +2,7 @@ package deviant import ( "encoding/json" + "fmt" "net/http" "net/url" "regexp" @@ -10,10 +11,10 @@ import ( "time" "github.com/VTGare/boe-tea-go/artworks" - "github.com/VTGare/boe-tea-go/artworks/embed" "github.com/VTGare/boe-tea-go/internal/arrays" "github.com/VTGare/boe-tea-go/messages" "github.com/VTGare/boe-tea-go/store" + "github.com/VTGare/embeds" "github.com/bwmarrin/discordgo" ) @@ -32,7 +33,6 @@ type Artwork struct { Comments int AIGenerated bool CreatedAt time.Time - artworkID string url string } @@ -65,46 +65,52 @@ type deviantEmbed struct { func New() artworks.Provider { return &DeviantArt{ - regex: regexp.MustCompile(`(?i)https://(?:www\.)?deviantart\.com/\w+/art/([\w\-]+)`), + regex: regexp.MustCompile(`(?i)https:\/\/(?:www\.)?deviantart\.com\/[\w]+\/art\/([\w\-]+)`), } } func (d *DeviantArt) Find(id string) (artworks.Artwork, error) { - return artworks.NewError(d, func() (artworks.Artwork, error) { - reqURL := "https://backend.deviantart.com/oembed?url=" + url.QueryEscape("deviantart.com/art/"+id) - resp, err := http.Get(reqURL) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - var res deviantEmbed - err = json.NewDecoder(resp.Body).Decode(&res) - if err != nil { - return nil, err - } - - artwork := &Artwork{ - Title: res.Title, - Author: &Author{ - Name: res.AuthorName, - URL: res.AuthorURL, - }, - ImageURL: res.URL, - ThumbnailURL: res.ThumbnailURL, - Tags: strings.Split(res.Tags, ", "), - Views: res.Community.Statistics.Attributes.Views, - Favorites: res.Community.Statistics.Attributes.Favorites, - Comments: res.Community.Statistics.Attributes.Comments, - CreatedAt: res.Pubdate, - artworkID: id, - url: res.AuthorURL + "/art/" + id, - } - - artwork.AIGenerated = artworks.IsAIGenerated(artwork.Tags...) - - return artwork, nil - }) + artwork, err := d._find(id) + if err != nil { + return nil, artworks.NewError(d, err) + } + + return artwork, nil +} + +func (d *DeviantArt) _find(id string) (artworks.Artwork, error) { + reqURL := "https://backend.deviantart.com/oembed?url=" + url.QueryEscape("deviantart.com/art/"+id) + resp, err := http.Get(reqURL) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var res deviantEmbed + err = json.NewDecoder(resp.Body).Decode(&res) + if err != nil { + return nil, err + } + + artwork := &Artwork{ + Title: res.Title, + Author: &Author{ + Name: res.AuthorName, + URL: res.AuthorURL, + }, + ImageURL: res.URL, + ThumbnailURL: res.ThumbnailURL, + Tags: strings.Split(res.Tags, ", "), + Views: res.Community.Statistics.Attributes.Views, + Favorites: res.Community.Statistics.Attributes.Favorites, + Comments: res.Community.Statistics.Attributes.Comments, + CreatedAt: res.Pubdate, + url: res.AuthorURL + "/art/" + id, + } + + artwork.AIGenerated = artworks.IsAIGenerated(artwork.Tags...) + + return artwork, nil } func (d *DeviantArt) Match(s string) (string, bool) { @@ -121,28 +127,36 @@ func (d *DeviantArt) Enabled(g *store.Guild) bool { } func (a *Artwork) MessageSends(footer string, tagsEnabled bool) ([]*discordgo.MessageSend, error) { - eb := &embed.Embed{ - Title: a.Title, - Username: a.Author.Name, - FieldName1: "Views", - FieldValue1: strconv.Itoa(a.Views), - FieldName2: "Favorites", - FieldValue2: []string{strconv.Itoa(a.Favorites)}, - Images: []string{a.ImageURL}, - URL: a.url, - Timestamp: a.CreatedAt, - Footer: footer, - AIGenerated: a.AIGenerated, - } + eb := embeds.NewBuilder() + + eb.Title(fmt.Sprintf("%v by %v", a.Title, a.Author.Name)). + Image(a.ImageURL). + URL(a.url). + Timestamp(a.CreatedAt). + AddField("Views", strconv.Itoa(a.Views), true). + AddField("Favorites", strconv.Itoa(a.Favorites), true) if tagsEnabled && len(a.Tags) > 0 { tags := arrays.Map(a.Tags, func(s string) string { - return messages.NamedLink(s, "https://www.deviantart.com/tag/"+s) + return messages.NamedLink( + s, "https://www.deviantart.com/tag/"+s, + ) }) - eb.Tags = strings.Join(tags, " • ") + + eb.Description("**Tags:**\n" + strings.Join(tags, " • ")) + } + + if footer != "" { + eb.Footer(footer, "") + } + + if a.AIGenerated { + eb.AddField("⚠️ Disclaimer", "This artwork is AI-generated.") } - return eb.ToEmbed(), nil + return []*discordgo.MessageSend{ + {Embeds: []*discordgo.MessageEmbed{eb.Finalize()}}, + }, nil } func (a *Artwork) StoreArtwork() *store.Artwork { @@ -154,10 +168,6 @@ func (a *Artwork) StoreArtwork() *store.Artwork { } } -func (a *Artwork) ArtworkID() string { - return a.artworkID -} - func (a *Artwork) URL() string { return a.url } diff --git a/artworks/embed/embed.go b/artworks/embed/embed.go deleted file mode 100644 index e3cb8f5..0000000 --- a/artworks/embed/embed.go +++ /dev/null @@ -1,93 +0,0 @@ -package embed - -import ( - "fmt" - "strings" - "time" - - "github.com/VTGare/boe-tea-go/internal/dgoutils" - "github.com/VTGare/embeds" - "github.com/bwmarrin/discordgo" -) - -type Embed struct { - Title string - Username string - Description string - Tags string - FieldName1 string - FieldValue1 string - FieldName2 string - FieldValue2 []string - Images []string - Files []*discordgo.File - URL string - Timestamp time.Time - Footer string - AIGenerated bool -} - -func (e *Embed) ToEmbed() []*discordgo.MessageSend { - var ( - length = dgoutils.Ternary(len(e.Files) > 0, 1, len(e.Images)) - pages = make([]*discordgo.MessageSend, 0, length) - ) - - for i := 0; i < length; i++ { - eb := embeds.NewBuilder() - - eb.Title(EscapeMarkdown( - dgoutils.Ternary(length == 1, - fmt.Sprintf("%v by %v", e.Title, e.Username), - fmt.Sprintf("%v by %v | Page %v / %v", e.Title, e.Username, i+1, length), - ), - )) - - if len(e.Images) != 0 { - eb.Image(e.Images[i]) - } - - eb.URL(e.URL) - eb.Timestamp(e.Timestamp) - - if i == 0 { - if e.Description != "" { - eb.Description(EscapeMarkdown(e.Description)) - } - - if e.Tags != "" { - eb.AddField("Tags", e.Tags) - } - } - - if i < len(e.FieldValue2) { - eb.AddField(e.FieldName1, e.FieldValue1, true) - eb.AddField(e.FieldName2, e.FieldValue2[i], true) - } - - if i == 0 && e.AIGenerated { - eb.AddField("⚠️ Disclaimer", "This artwork is AI-generated.") - } - - if e.Footer != "" { - eb.Footer(e.Footer, "") - } - - pages = append(pages, &discordgo.MessageSend{ - Embeds: []*discordgo.MessageEmbed{eb.Finalize()}, - Files: e.Files, - }) - } - - return pages -} - -func EscapeMarkdown(content string) string { - markdown := []string{"-", "_", "#", "*", "`", ">"} - - for _, m := range markdown { - content = strings.ReplaceAll(content, m, "\\"+m) - } - - return content -} diff --git a/artworks/error.go b/artworks/error.go deleted file mode 100644 index 0bd559d..0000000 --- a/artworks/error.go +++ /dev/null @@ -1,38 +0,0 @@ -package artworks - -import ( - "errors" - "fmt" -) - -// Common errors -var ( - ErrArtworkNotFound = errors.New("artwork not found") - ErrRateLimited = errors.New("provider rate limited") -) - -type Error struct { - provider string - cause error -} - -func (e *Error) Error() string { - return fmt.Sprintf("provider %v returned an error: %v", e.provider, e.cause.Error()) -} - -func (e *Error) Unwrap() error { - return e.cause -} - -func NewError(p Provider, find func() (Artwork, error)) (Artwork, error) { - artwork, err := find() - - if err != nil { - return nil, &Error{ - provider: fmt.Sprintf("%T", p), - cause: err, - } - } - - return artwork, nil -} diff --git a/artworks/pixiv/pixiv.go b/artworks/pixiv/pixiv.go index 44354c5..acfa4e3 100644 --- a/artworks/pixiv/pixiv.go +++ b/artworks/pixiv/pixiv.go @@ -8,19 +8,21 @@ import ( "time" "github.com/VTGare/boe-tea-go/artworks" - "github.com/VTGare/boe-tea-go/artworks/embed" "github.com/VTGare/boe-tea-go/internal/arrays" - "github.com/VTGare/boe-tea-go/internal/dgoutils" "github.com/VTGare/boe-tea-go/messages" "github.com/VTGare/boe-tea-go/store" + "github.com/VTGare/embeds" "github.com/bwmarrin/discordgo" "github.com/everpcpc/pixiv" ) +var regex = regexp.MustCompile( + `(?i)http(?:s)?:\/\/(?:www\.)?pixiv\.net\/(?:en\/)?(?:artworks\/|member_illust\.php\?)(?:mode=medium\&)?(?:illust_id=)?([0-9]+)`, +) + type Pixiv struct { app *pixiv.AppPixivAPI proxyHost string - regex *regexp.Regexp } type Artwork struct { @@ -45,15 +47,12 @@ type Image struct { Original string } -func LoadAuth(authToken, refreshToken string) error { +func New(proxyHost, authToken, refreshToken string) (artworks.Provider, error) { _, err := pixiv.LoadAuth(authToken, refreshToken, time.Now()) if err != nil { - return err + return nil, err } - return nil -} -func New(proxyHost string) artworks.Provider { if proxyHost == "" { proxyHost = "https://boetea.dev" } @@ -61,12 +60,11 @@ func New(proxyHost string) artworks.Provider { return &Pixiv{ app: pixiv.NewApp(), proxyHost: proxyHost, - regex: regexp.MustCompile(`(?i)https?://(?:www\.)?pixiv\.net/(?:en/)?(?:artworks/|member_illust\.php\?)(?:mode=medium&)?(?:illust_id=)?([0-9]+)`), - } + }, nil } func (p *Pixiv) Match(s string) (string, bool) { - res := p.regex.FindStringSubmatch(s) + res := regex.FindStringSubmatch(s) if res == nil { return "", false } @@ -75,83 +73,103 @@ func (p *Pixiv) Match(s string) (string, bool) { } func (p *Pixiv) Find(id string) (artworks.Artwork, error) { - return artworks.NewError(p, func() (artworks.Artwork, error) { - i, err := strconv.ParseUint(id, 10, 64) - if err != nil { - return nil, err - } + artwork, err := p._find(id) + if err != nil { + return nil, artworks.NewError(p, err) + } - illust, err := p.app.IllustDetail(i) - if err != nil { - return nil, err - } + return artwork, nil +} - if illust.ID == 0 { - return nil, artworks.ErrArtworkNotFound - } +func (p *Pixiv) _find(id string) (artworks.Artwork, error) { + i, err := strconv.ParseUint(id, 10, 64) + if err != nil { + return nil, err + } - tags := make([]string, 0) - nsfw := false - for _, tag := range illust.Tags { - if tag.Name == "R-18" { - nsfw = true - } + illust, err := p.app.IllustDetail(i) + if err != nil { + return nil, err + } - tags = dgoutils.Ternary(tag.TranslatedName != "", - append(tags, tag.TranslatedName), - append(tags, tag.Name), - ) - } + if illust.ID == 0 { + return nil, artworks.ErrArtworkNotFound + } - images := make([]*Image, 0, illust.PageCount) - if page := illust.MetaSinglePage; page != nil { - if page.OriginalImageURL != "" { - img := &Image{ - Original: page.OriginalImageURL, - Preview: illust.Images.Medium, - } + author := "" + if illust.User != nil { + author = illust.User.Name + } else { + author = "Unknown" + } - images = append(images, img) - } + tags := make([]string, 0) + nsfw := false + for _, tag := range illust.Tags { + if tag.Name == "R-18" { + nsfw = true } - for _, page := range illust.MetaPages { + if tag.TranslatedName != "" { + tags = append(tags, tag.TranslatedName) + } else { + tags = append(tags, tag.Name) + } + } + + images := make([]*Image, 0, illust.PageCount) + if page := illust.MetaSinglePage; page != nil { + if page.OriginalImageURL != "" { img := &Image{ - Original: page.Images.Original, - Preview: page.Images.Large, + Original: page.OriginalImageURL, + Preview: illust.Images.Medium, } images = append(images, img) } + } - errImages := []string{ - "limit_sanity_level_360.png", - "limit_unknown_360.png", + for _, page := range illust.MetaPages { + img := &Image{ + Original: page.Images.Original, + Preview: page.Images.Large, } - for _, img := range errImages { - if images[0].Original == fmt.Sprintf("https://s.pximg.net/common/images/%s", img) { - return nil, artworks.ErrRateLimited - } + images = append(images, img) + } + + artwork := &Artwork{ + ID: id, + url: "https://www.pixiv.net/en/artworks/" + id, + Title: illust.Title, + Author: author, + Tags: tags, + Images: images, + NSFW: nsfw, + Type: illust.Type, + Pages: illust.PageCount, + Likes: illust.TotalBookmarks, + CreatedAt: illust.CreateDate, + + proxy: p.proxyHost, + } + + errImages := []string{ + "limit_sanity_level_360.png", + "limit_unknown_360.png", + } + + for _, img := range errImages { + if artwork.Images[0].Original == fmt.Sprintf("https://s.pximg.net/common/images/%s", img) { + return nil, artworks.ErrRateLimited } + } - return &Artwork{ - ID: id, - url: "https://www.pixiv.net/en/artworks/" + id, - Title: illust.Title, - Author: dgoutils.Ternary(illust.User != nil, illust.User.Name, "Unknown"), - Tags: tags, - Images: images, - NSFW: nsfw, - Type: illust.Type, - Pages: illust.PageCount, - Likes: illust.TotalBookmarks, - CreatedAt: illust.CreateDate, - AIGenerated: illust.IllustAIType == pixiv.IllustAITypeAIGenerated, - - proxy: p.proxyHost, - }, nil - }) + if illust.IllustAIType == pixiv.IllustAITypeAIGenerated { + artwork.AIGenerated = true + } + + return artwork, nil } func (p *Pixiv) Enabled(g *store.Guild) bool { @@ -168,35 +186,61 @@ func (a *Artwork) StoreArtwork() *store.Artwork { } func (a *Artwork) MessageSends(footer string, tagsEnabled bool) ([]*discordgo.MessageSend, error) { - eb := &embed.Embed{ - Title: a.Title, - Username: a.Author, - FieldName1: "Likes", - FieldValue1: strconv.Itoa(a.Likes), - FieldName2: "Original quality", - URL: a.url, - Timestamp: a.CreatedAt, - Footer: footer, - AIGenerated: a.AIGenerated, + var ( + length = len(a.Images) + pages = make([]*discordgo.MessageSend, 0, length) + eb = embeds.NewBuilder() + ) + + if length > 1 { + eb.Title(fmt.Sprintf("%v by %v | Page %v / %v", a.Title, a.Author, 1, length)) + } else { + eb.Title(fmt.Sprintf("%v by %v", a.Title, a.Author)) } if tagsEnabled && len(a.Tags) > 0 { tags := arrays.Map(a.Tags, func(s string) string { return fmt.Sprintf("[%v](https://pixiv.net/en/tags/%v/artworks)", s, s) }) - eb.Tags = strings.Join(tags, " • ") + + eb.Description(fmt.Sprintf("**Tags**\n%v", strings.Join(tags, " • "))) } - for _, image := range a.Images { - eb.Images = append(eb.Images, image.previewProxy(a.proxy)) - eb.FieldValue2 = append(eb.FieldValue2, messages.ClickHere(image.originalProxy(a.proxy))) + eb.URL(a.url). + AddField("Likes", strconv.Itoa(a.Likes), true). + AddField("Original quality", messages.ClickHere(a.Images[0].originalProxy(a.proxy)), true). + Timestamp(a.CreatedAt) + + if footer != "" { + eb.Footer(footer, "") } - return eb.ToEmbed(), nil -} + if a.AIGenerated { + eb.AddField("⚠️ Disclaimer", "This artwork is AI-generated.") + } + + eb.Image(a.Images[0].previewProxy(a.proxy)) + pages = append(pages, &discordgo.MessageSend{Embeds: []*discordgo.MessageEmbed{eb.Finalize()}}) + if length > 1 { + for ind, image := range a.Images[1:] { + eb := embeds.NewBuilder() + + eb.Title(fmt.Sprintf("%v by %v | Page %v / %v", a.Title, a.Author, ind+2, length)) + eb.Image(image.previewProxy(a.proxy)) + eb.URL(a.url).Timestamp(a.CreatedAt) + + if footer != "" { + eb.Footer(footer, "") + } + + eb.AddField("Likes", strconv.Itoa(a.Likes), true) + eb.AddField("Original quality", messages.ClickHere(image.originalProxy(a.proxy)), true) + + pages = append(pages, &discordgo.MessageSend{Embeds: []*discordgo.MessageEmbed{eb.Finalize()}}) + } + } -func (a *Artwork) ArtworkID() string { - return a.ID + return pages, nil } func (a *Artwork) URL() string { diff --git a/artworks/pixiv/pixiv_suite_test.go b/artworks/pixiv/pixiv_suite_test.go index 9c13139..f83c033 100644 --- a/artworks/pixiv/pixiv_suite_test.go +++ b/artworks/pixiv/pixiv_suite_test.go @@ -16,7 +16,7 @@ func TestPixiv(t *testing.T) { var _ = DescribeTable( "Match Pixiv URL", func(url string, expectedID string, expectedResult bool) { - provider := pixiv.New("") + provider := pixiv.Pixiv{} id, ok := provider.Match(url) Expect(id).To(BeEquivalentTo(expectedID)) diff --git a/artworks/twitter/fxtwitter.go b/artworks/twitter/fxtwitter.go index e6d477f..06745c0 100644 --- a/artworks/twitter/fxtwitter.go +++ b/artworks/twitter/fxtwitter.go @@ -12,10 +12,11 @@ import ( "github.com/VTGare/boe-tea-go/internal/arrays" ) +var nonAlphanumericRegex = regexp.MustCompile(`[^\p{L}\p{N} -]+`) + type fxTwitter struct { twitterMatcher - client *http.Client - nonAlphanumericRegex *regexp.Regexp + client *http.Client } type fxTwitterResponse struct { @@ -53,13 +54,10 @@ type fxTwitterResponse struct { } `json:"tweet,omitempty"` } -func newFxTwitter(re *regexp.Regexp) artworks.Provider { +func newFxTwitter() artworks.Provider { return &fxTwitter{ - client: &http.Client{}, - nonAlphanumericRegex: regexp.MustCompile(`[^\p{L}\p{N} -]+`), - twitterMatcher: twitterMatcher{ - regex: re, - }, + twitterMatcher: twitterMatcher{}, + client: &http.Client{}, } } @@ -129,7 +127,7 @@ func (fxt *fxTwitter) Find(id string) (artworks.Artwork, error) { } artwork.AIGenerated = artworks.IsAIGenerated(arrays.Map(strings.Fields(artwork.Content), func(s string) string { - return fxt.nonAlphanumericRegex.ReplaceAllString(s, "") + return nonAlphanumericRegex.ReplaceAllString(s, "") })...) return artwork, nil diff --git a/artworks/twitter/matcher.go b/artworks/twitter/matcher.go index 60e8e4f..cef5453 100644 --- a/artworks/twitter/matcher.go +++ b/artworks/twitter/matcher.go @@ -2,24 +2,21 @@ package twitter import ( "net/url" - "regexp" "strconv" "strings" "github.com/VTGare/boe-tea-go/store" ) -type twitterMatcher struct { - regex *regexp.Regexp -} +type twitterMatcher struct{} -func (t twitterMatcher) Match(s string) (string, bool) { +func (twitterMatcher) Match(s string) (string, bool) { u, err := url.ParseRequestURI(s) if err != nil { return "", false } - if ok := t.regex.MatchString(u.Host); !ok { + if !strings.Contains(u.Host, "twitter.com") && u.Host != "x.com" { return "", false } diff --git a/artworks/twitter/twitter.go b/artworks/twitter/twitter.go index 8979ea7..cb6f84f 100644 --- a/artworks/twitter/twitter.go +++ b/artworks/twitter/twitter.go @@ -4,11 +4,9 @@ import ( "bytes" "errors" "fmt" - "github.com/VTGare/boe-tea-go/artworks/embed" "io" "net/http" "net/url" - "regexp" "strconv" "strings" "time" @@ -53,40 +51,33 @@ type Video struct { } func New() artworks.Provider { - re := regexp.MustCompile(`^(?:mobile\.)?(?:(?:fix(?:up|v))?x|(?:[fv]x)?twitter)\.com$`) - return &Twitter{ - providers: []artworks.Provider{newFxTwitter(re)}, - twitterMatcher: twitterMatcher{ - regex: re, - }, + providers: []artworks.Provider{newFxTwitter()}, } } func (t *Twitter) Find(id string) (artworks.Artwork, error) { - return artworks.NewError(t, func() (artworks.Artwork, error) { - var ( - artwork artworks.Artwork - errs []error - ) - - for _, provider := range t.providers { - var err error - artwork, err = provider.Find(id) - if errors.Is(err, ErrTweetNotFound) || errors.Is(err, ErrPrivateAccount) { - return nil, err - } - - if err != nil { - errs = append(errs, err) - continue - } + var ( + artwork artworks.Artwork + errs []error + ) + + for _, provider := range t.providers { + var err error + artwork, err = provider.Find(id) + if errors.Is(err, ErrTweetNotFound) || errors.Is(err, ErrPrivateAccount) { + return nil, artworks.NewError(t, err) + } - return artwork, nil + if err != nil { + errs = append(errs, err) + continue } - return &Artwork{}, errors.Join(errs...) - }) + return artwork, nil + } + + return &Artwork{}, artworks.NewError(t, errors.Join(errs...)) } func (a *Artwork) StoreArtwork() *store.Artwork { @@ -106,8 +97,8 @@ func (a *Artwork) StoreArtwork() *store.Artwork { // MessageSends transforms an artwork to discordgo embeds. func (a *Artwork) MessageSends(footer string, _ bool) ([]*discordgo.MessageSend, error) { + eb := embeds.NewBuilder() if a.FullName == "" && a.Len() == 0 { - eb := embeds.NewBuilder() eb.Title("❎ Tweet doesn't exist.") eb.Description("The tweet is NSFW or doesn't exist.\n\nUnsafe tweets can't be embedded due to API changes.") eb.Footer(footer, "") @@ -117,41 +108,80 @@ func (a *Artwork) MessageSends(footer string, _ bool) ([]*discordgo.MessageSend, }, nil } - eb := &embed.Embed{ - Title: a.FullName, - Username: a.Username, - Description: a.Content, - FieldName1: "Likes", - FieldValue1: strconv.Itoa(a.Likes), - FieldName2: "Retweets", - FieldValue2: []string{strconv.Itoa(a.Retweets)}, - URL: a.Permalink, - Timestamp: a.Timestamp, - AIGenerated: a.AIGenerated, + eb.URL(a.Permalink).Description(artworks.EscapeMarkdown(a.Content)).Timestamp(a.Timestamp) + + if a.Retweets > 0 { + eb.AddField("Retweets", strconv.Itoa(a.Retweets), true) + } + + if a.Likes > 0 { + eb.AddField("Likes", strconv.Itoa(a.Likes), true) + } + + if footer != "" { + eb.Footer(footer, "") + } + + if a.AIGenerated { + eb.AddField("⚠️ Disclaimer", "This artwork is AI-generated.") } if len(a.Videos) > 0 { return a.videoEmbed(eb) } - for _, image := range a.Photos { - eb.Images = append(eb.Images, image) + length := len(a.Photos) + tweets := make([]*discordgo.MessageSend, 0, length) + if length > 1 { + eb.Title(fmt.Sprintf("%v (%v) | Page %v / %v", a.FullName, a.Username, 1, length)) + } else { + eb.Title(fmt.Sprintf("%v (%v)", a.FullName, a.Username)) + } + + if length > 0 { + eb.Image(a.Photos[0]) + } + + tweets = append(tweets, &discordgo.MessageSend{ + Embeds: []*discordgo.MessageEmbed{eb.Finalize()}, + }) + + if len(a.Photos) > 1 { + for ind, photo := range a.Photos[1:] { + eb := embeds.NewBuilder() + + eb.Title(fmt.Sprintf("%v (%v) | Page %v / %v", a.FullName, a.Username, ind+2, length)).URL(a.Permalink) + eb.Image(photo).Timestamp(a.Timestamp) + + if footer != "" { + eb.Footer(footer, "") + } + + tweets = append(tweets, &discordgo.MessageSend{Embeds: []*discordgo.MessageEmbed{eb.Finalize()}}) + } } - return eb.ToEmbed(), nil + return tweets, nil } -func (a *Artwork) videoEmbed(eb *embed.Embed) ([]*discordgo.MessageSend, error) { +func (a *Artwork) videoEmbed(eb *embeds.Builder) ([]*discordgo.MessageSend, error) { + files := make([]*discordgo.File, 0, len(a.Videos)) for _, video := range a.Videos { file, err := downloadVideo(video.URL) if err != nil { return nil, err } - eb.Files = append(eb.Files, file) + files = append(files, file) } - return eb.ToEmbed(), nil + eb.Title(fmt.Sprintf("%v (%v)", a.FullName, a.Username)) + msg := &discordgo.MessageSend{ + Embeds: []*discordgo.MessageEmbed{eb.Finalize()}, + Files: files, + } + + return []*discordgo.MessageSend{msg}, nil } func downloadVideo(fileURL string) (*discordgo.File, error) { @@ -180,10 +210,6 @@ func downloadVideo(fileURL string) (*discordgo.File, error) { }, nil } -func (a *Artwork) ArtworkID() string { - return a.ID -} - func (a *Artwork) URL() string { return a.Permalink } diff --git a/artworks/twitter/twitter_suite_test.go b/artworks/twitter/twitter_suite_test.go index 232b6d4..5293e4b 100644 --- a/artworks/twitter/twitter_suite_test.go +++ b/artworks/twitter/twitter_suite_test.go @@ -24,8 +24,7 @@ var _ = DescribeTable( }, Entry("Valid artwork", "https://twitter.com/watsonameliaEN/status/1371674594675937282", "1371674594675937282", true), Entry("Query params", "https://twitter.com/watsonameliaEN/status/1371674594675937282?param=1", "1371674594675937282", true), - Entry("Mobile Twitter URL", "https://mobile.twitter.com/watsonameliaEN/status/1371674594675937282", "1371674594675937282", true), - Entry("Mobile X URL", "https://mobile.x.com/watsonameliaEN/status/1371674594675937282", "1371674594675937282", true), + Entry("Mobile URL", "https://mobile.twitter.com/watsonameliaEN/status/1371674594675937282", "1371674594675937282", true), Entry("No username", "https://twitter.com/i/status/1371674594675937282", "1371674594675937282", true), Entry("iweb URL", "https://twitter.com/i/web/status/1371674594675937282", "1371674594675937282", true), Entry("With photo suffix", "https://twitter.com/i/web/status/1371674594675937282/photo/1", "1371674594675937282", true), @@ -33,9 +32,6 @@ var _ = DescribeTable( Entry("ID with letters", "https://twitter.com/i/web/status/1371674594675937282f", "", false), Entry("Different domain", "https://google.com/i/status/123456", "", false), Entry("Invalid URL", "efe", "", false), - Entry("fxtwitter link", "https://fxtwitter.com/i/status/1234", "1234", true), Entry("vxtwitter link", "https://vxtwitter.com/i/status/1234", "1234", true), Entry("X link", "https://x.com/i/status/1234", "1234", true), - Entry("fixupx link", "https://fixupx.com/i/status/1234", "1234", true), - Entry("fixvx link", "https://fixvx.com/i/status/1234", "1234", true), ) From 8e5c6f2d861cbd64e1eee872287d8efa30851c95 Mon Sep 17 00:00:00 2001 From: VTGare Date: Sun, 17 Nov 2024 17:42:51 +0200 Subject: [PATCH 26/30] remove artstation/restore some changes --- artworks/artstation/artstation.go | 207 ------------------- artworks/artstation/artstation_suite_test.go | 28 --- artworks/artworks.go | 21 +- artworks/deviant/deviant.go | 18 +- artworks/errors.go | 37 ++++ artworks/pixiv/pixiv.go | 27 ++- artworks/twitter/fxtwitter.go | 2 +- artworks/twitter/twitter.go | 6 +- cmd/boetea/main.go | 3 - commands/settings.go | 15 -- go.mod | 3 - go.sum | 6 - messages/embeds.go | 5 - post/post.go | 4 +- store/guilds.go | 7 +- store/stateful.go | 8 +- 16 files changed, 82 insertions(+), 315 deletions(-) delete mode 100644 artworks/artstation/artstation.go delete mode 100644 artworks/artstation/artstation_suite_test.go create mode 100644 artworks/errors.go diff --git a/artworks/artstation/artstation.go b/artworks/artstation/artstation.go deleted file mode 100644 index 33d816e..0000000 --- a/artworks/artstation/artstation.go +++ /dev/null @@ -1,207 +0,0 @@ -package artstation - -import ( - "encoding/json" - "fmt" - "net/http" - "regexp" - "strconv" - "time" - - "github.com/VTGare/boe-tea-go/artworks" - "github.com/VTGare/boe-tea-go/store" - "github.com/VTGare/embeds" - "github.com/bwmarrin/discordgo" - "github.com/microcosm-cc/bluemonday" -) - -type Artstation struct { - regex *regexp.Regexp -} - -type ArtstationResponse struct { - Title string `json:"title,omitempty"` - Description string `json:"description,omitempty"` - Permalink string `json:"permalink,omitempty"` - CoverURL string `json:"cover_url,omitempty"` - HashID string `json:"hash_id,omitempty"` - Tags []string `json:"tags,omitempty"` - Assets []*Asset `json:"assets,omitempty"` - User *User `json:"user,omitempty"` - - Medium *Category `json:"medium,omitempty"` - Mediums []*Category `json:"mediums,omitempty"` - Categories []*Category `json:"categories,omitempty"` - - ViewsCount int `json:"views_count,omitempty"` - LikesCount int `json:"likes_count,omitempty"` - CommentsCount int `json:"comments_count,omitempty"` - - HideAsAdult bool `json:"hide_as_adult,omitempty"` - VisibleOnArtstation bool `json:"visible_on_artstation,omitempty"` - - AIGenerated bool - CreatedAt time.Time `json:"created_at,omitempty"` -} - -type Asset struct { - Title string `json:"title,omitempty"` - TitleFormatted string `json:"title_formatted,omitempty"` - ImageURL string `json:"image_url,omitempty"` - Width int `json:"width,omitempty"` - Height int `json:"height,omitempty"` - AssetType string `json:"asset_type,omitempty"` - HasImage bool `json:"has_image,omitempty"` - HasEmbeddedPlayer bool `json:"has_embedded_player,omitempty"` -} - -type User struct { - Name string `json:"username,omitempty"` - Headline string `json:"headline,omitempty"` - FullName string `json:"full_name,omitempty"` - Permalink string `json:"permalink,omitempty"` - MediumAvatarURL string `json:"medium_avatar_url,omitempty"` - LargeAvatarURL string `json:"large_avatar_url,omitempty"` - SmallAvatarURL string `json:"small_avatar_url,omitempty"` -} - -type Category struct { - ID int - Name string -} - -func New() artworks.Provider { - r := regexp.MustCompile(`(?i)https:\/\/(?:www\.)?artstation\.com\/artwork\/([\w\-]+)`) - - return &Artstation{ - regex: r, - } -} - -func (as *Artstation) Find(id string) (artworks.Artwork, error) { - artwork, err := as._find(id) - if err != nil { - return nil, artworks.NewError(as, err) - } - - return artwork, nil -} - -func (as *Artstation) _find(id string) (artworks.Artwork, error) { - reqURL := fmt.Sprintf("https://www.artstation.com/projects/%v.json", id) - resp, err := http.Get(reqURL) - if err != nil { - return nil, err - } - - defer resp.Body.Close() - - res := &ArtstationResponse{} - err = json.NewDecoder(resp.Body).Decode(res) - if err != nil { - return nil, err - } - - res.AIGenerated = artworks.IsAIGenerated(res.Tags...) - - return res, nil -} - -func (as *Artstation) Match(url string) (string, bool) { - res := as.regex.FindStringSubmatch(url) - if res == nil { - return "", false - } - - return res[1], true -} - -func (*Artstation) Enabled(g *store.Guild) bool { - return g.Artstation -} - -func (artwork *ArtstationResponse) StoreArtwork() *store.Artwork { - images := make([]string, 0, len(artwork.Assets)) - for _, asset := range artwork.Assets { - images = append(images, asset.ImageURL) - } - - return &store.Artwork{ - Title: artwork.Title, - Author: artwork.User.Name, - URL: artwork.Permalink, - Images: images, - } -} - -func (artwork *ArtstationResponse) MessageSends(footer string, tagsEnabled bool) ([]*discordgo.MessageSend, error) { - var ( - length = len(artwork.Assets) - pages = make([]*discordgo.MessageSend, 0, length) - eb = embeds.NewBuilder() - ) - - if length == 0 { - eb.Title("❎ An error has occured.") - eb.Description("Artwork has been deleted or the ID does not exist.") - eb.Footer(footer, "") - - return []*discordgo.MessageSend{ - {Embeds: []*discordgo.MessageEmbed{eb.Finalize()}}, - }, nil - } - - if length > 1 { - eb.Title(fmt.Sprintf("%v by %v | Page %v / %v", artwork.Title, artwork.User.Name, 1, length)) - } else { - eb.Title(fmt.Sprintf("%v by %v", artwork.Title, artwork.User.Name)) - } - - if tagsEnabled { - desc := bluemonday.StrictPolicy().Sanitize(artwork.Description) - eb.Description(artworks.EscapeMarkdown(desc)) - } - - eb.URL(artwork.URL()). - AddField("Likes", strconv.Itoa(artwork.LikesCount), true). - AddField("Views", strconv.Itoa(artwork.ViewsCount), true). - Timestamp(artwork.CreatedAt) - - if footer != "" { - eb.Footer(footer, "") - } - - if artwork.AIGenerated { - eb.AddField("⚠️ Disclaimer", "This artwork is AI-generated.") - } - - eb.Image(artwork.Assets[0].ImageURL) - pages = append(pages, &discordgo.MessageSend{Embeds: []*discordgo.MessageEmbed{eb.Finalize()}}) - if length > 1 { - for ind, image := range artwork.Assets[1:] { - eb := embeds.NewBuilder() - - eb.Title(fmt.Sprintf("%v by %v | Page %v / %v", artwork.Title, artwork.User.Name, ind+2, length)). - Image(image.ImageURL). - URL(artwork.URL()). - Timestamp(artwork.CreatedAt) - - if footer != "" { - eb.Footer(footer, "") - } - - eb.AddField("Likes", strconv.Itoa(artwork.LikesCount), true) - pages = append(pages, &discordgo.MessageSend{Embeds: []*discordgo.MessageEmbed{eb.Finalize()}}) - } - } - - return pages, nil -} - -func (artwork *ArtstationResponse) URL() string { - return artwork.Permalink -} - -func (artwork *ArtstationResponse) Len() int { - return len(artwork.Assets) -} diff --git a/artworks/artstation/artstation_suite_test.go b/artworks/artstation/artstation_suite_test.go deleted file mode 100644 index 7e3d46c..0000000 --- a/artworks/artstation/artstation_suite_test.go +++ /dev/null @@ -1,28 +0,0 @@ -package artstation_test - -import ( - "testing" - - "github.com/VTGare/boe-tea-go/artworks/artstation" - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -func TestArtstation(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Artstation Suite") -} - -var _ = DescribeTable( - "Match Artstation URL", - func(url string, expectedID string, expectedResult bool) { - as := artstation.New() - - id, ok := as.Match(url) - Expect(id).To(BeEquivalentTo(expectedID)) - Expect(ok).To(BeEquivalentTo(expectedResult)) - }, - Entry("Valid artstation artwork", "https://www.artstation.com/artwork/q98e9N", "q98e9N", true), - Entry("Different domain", "https://www.somethingelse.com/artwork/q98e9N", "", false), - Entry("Query params", "https://www.artstation.com/artwork/q98e9N?iw=234", "q98e9N", true), -) diff --git a/artworks/artworks.go b/artworks/artworks.go index c5273af..f876cb4 100644 --- a/artworks/artworks.go +++ b/artworks/artworks.go @@ -1,7 +1,6 @@ package artworks import ( - "errors" "fmt" "regexp" "strings" @@ -19,23 +18,11 @@ type Provider interface { type Artwork interface { StoreArtwork() *store.Artwork MessageSends(footer string, tags bool) ([]*discordgo.MessageSend, error) + ID() string URL() string Len() int } -type Error struct { - provider string - cause error -} - -func (e *Error) Error() string { - return fmt.Sprintf("provider %v returned an error: %v", e.provider, e.cause.Error()) -} - -func (e *Error) Unwrap() error { - return e.cause -} - func NewError(p Provider, err error) error { return &Error{ provider: fmt.Sprintf("%T", p), @@ -43,12 +30,6 @@ func NewError(p Provider, err error) error { } } -// Common errors -var ( - ErrArtworkNotFound = errors.New("artwork not found") - ErrRateLimited = errors.New("provider rate limited") -) - func EscapeMarkdown(content string) string { contents := strings.Split(content, "\n") regex := regexp.MustCompile("^#{1,3}") diff --git a/artworks/deviant/deviant.go b/artworks/deviant/deviant.go index 87f027d..36da5e2 100644 --- a/artworks/deviant/deviant.go +++ b/artworks/deviant/deviant.go @@ -33,7 +33,9 @@ type Artwork struct { Comments int AIGenerated bool CreatedAt time.Time - url string + + id string + url string } type Author struct { @@ -78,7 +80,7 @@ func (d *DeviantArt) Find(id string) (artworks.Artwork, error) { return artwork, nil } -func (d *DeviantArt) _find(id string) (artworks.Artwork, error) { +func (*DeviantArt) _find(id string) (artworks.Artwork, error) { reqURL := "https://backend.deviantart.com/oembed?url=" + url.QueryEscape("deviantart.com/art/"+id) resp, err := http.Get(reqURL) if err != nil { @@ -105,7 +107,9 @@ func (d *DeviantArt) _find(id string) (artworks.Artwork, error) { Favorites: res.Community.Statistics.Attributes.Favorites, Comments: res.Community.Statistics.Attributes.Comments, CreatedAt: res.Pubdate, - url: res.AuthorURL + "/art/" + id, + + id: id, + url: res.AuthorURL + "/art/" + id, } artwork.AIGenerated = artworks.IsAIGenerated(artwork.Tags...) @@ -122,7 +126,7 @@ func (d *DeviantArt) Match(s string) (string, bool) { return res[1], true } -func (d *DeviantArt) Enabled(g *store.Guild) bool { +func (*DeviantArt) Enabled(g *store.Guild) bool { return g.Deviant } @@ -172,6 +176,10 @@ func (a *Artwork) URL() string { return a.url } -func (a *Artwork) Len() int { +func (a *Artwork) ID() string { + return a.id +} + +func (*Artwork) Len() int { return 1 } diff --git a/artworks/errors.go b/artworks/errors.go new file mode 100644 index 0000000..759b9d3 --- /dev/null +++ b/artworks/errors.go @@ -0,0 +1,37 @@ +package artworks + +import ( + "errors" + "fmt" +) + +// Common errors +var ( + ErrArtworkNotFound = errors.New("artwork not found") + ErrRateLimited = errors.New("provider rate limited") +) + +type Error struct { + provider string + cause error +} + +func (e *Error) Error() string { + return fmt.Sprintf("provider %v returned an error: %v", e.provider, e.cause.Error()) +} + +func (e *Error) Unwrap() error { + return e.cause +} + +func WrapError(p Provider, find func() (Artwork, error)) (Artwork, error) { + artwork, err := find() + if err != nil { + return nil, &Error{ + provider: fmt.Sprintf("%T", p), + cause: err, + } + } + + return artwork, nil +} diff --git a/artworks/pixiv/pixiv.go b/artworks/pixiv/pixiv.go index acfa4e3..b92ada1 100644 --- a/artworks/pixiv/pixiv.go +++ b/artworks/pixiv/pixiv.go @@ -16,17 +16,13 @@ import ( "github.com/everpcpc/pixiv" ) -var regex = regexp.MustCompile( - `(?i)http(?:s)?:\/\/(?:www\.)?pixiv\.net\/(?:en\/)?(?:artworks\/|member_illust\.php\?)(?:mode=medium\&)?(?:illust_id=)?([0-9]+)`, -) - type Pixiv struct { app *pixiv.AppPixivAPI proxyHost string + regex *regexp.Regexp } type Artwork struct { - ID string Type string Author string Title string @@ -38,6 +34,7 @@ type Artwork struct { AIGenerated bool CreatedAt time.Time + id string url string proxy string } @@ -47,12 +44,15 @@ type Image struct { Original string } -func New(proxyHost, authToken, refreshToken string) (artworks.Provider, error) { +func LoadAuth(authToken, refreshToken string) error { _, err := pixiv.LoadAuth(authToken, refreshToken, time.Now()) if err != nil { - return nil, err + return err } + return nil +} +func New(proxyHost string) artworks.Provider { if proxyHost == "" { proxyHost = "https://boetea.dev" } @@ -60,11 +60,12 @@ func New(proxyHost, authToken, refreshToken string) (artworks.Provider, error) { return &Pixiv{ app: pixiv.NewApp(), proxyHost: proxyHost, - }, nil + regex: regexp.MustCompile(`(?i)https?://(?:www\.)?pixiv\.net/(?:en/)?(?:artworks/|member_illust\.php\?)(?:mode=medium&)?(?:illust_id=)?([0-9]+)`), + } } func (p *Pixiv) Match(s string) (string, bool) { - res := regex.FindStringSubmatch(s) + res := p.regex.FindStringSubmatch(s) if res == nil { return "", false } @@ -139,7 +140,7 @@ func (p *Pixiv) _find(id string) (artworks.Artwork, error) { } artwork := &Artwork{ - ID: id, + id: id, url: "https://www.pixiv.net/en/artworks/" + id, Title: illust.Title, Author: author, @@ -172,7 +173,7 @@ func (p *Pixiv) _find(id string) (artworks.Artwork, error) { return artwork, nil } -func (p *Pixiv) Enabled(g *store.Guild) bool { +func (*Pixiv) Enabled(g *store.Guild) bool { return g.Pixiv } @@ -251,6 +252,10 @@ func (a *Artwork) Len() int { return a.Pages } +func (a *Artwork) ID() string { + return a.id +} + func (a *Artwork) imageURLs() []string { urls := make([]string, 0, len(a.Images)) diff --git a/artworks/twitter/fxtwitter.go b/artworks/twitter/fxtwitter.go index 06745c0..680be17 100644 --- a/artworks/twitter/fxtwitter.go +++ b/artworks/twitter/fxtwitter.go @@ -114,7 +114,7 @@ func (fxt *fxTwitter) Find(id string) (artworks.Artwork, error) { artwork := &Artwork{ Videos: videos, Photos: photos, - ID: fxArtwork.Tweet.ID, + id: fxArtwork.Tweet.ID, FullName: fxArtwork.Tweet.Author.Name, Username: username, Content: fxArtwork.Tweet.Text, diff --git a/artworks/twitter/twitter.go b/artworks/twitter/twitter.go index cb6f84f..c5d4b75 100644 --- a/artworks/twitter/twitter.go +++ b/artworks/twitter/twitter.go @@ -32,7 +32,7 @@ type Twitter struct { type Artwork struct { Videos []Video Photos []string - ID string + id string FullName string Username string Content string @@ -164,6 +164,10 @@ func (a *Artwork) MessageSends(footer string, _ bool) ([]*discordgo.MessageSend, return tweets, nil } +func (a *Artwork) ID() string { + return a.id +} + func (a *Artwork) videoEmbed(eb *embeds.Builder) ([]*discordgo.MessageSend, error) { files := make([]*discordgo.File, 0, len(a.Videos)) for _, video := range a.Videos { diff --git a/cmd/boetea/main.go b/cmd/boetea/main.go index 5fc31e5..f33ce00 100644 --- a/cmd/boetea/main.go +++ b/cmd/boetea/main.go @@ -93,9 +93,6 @@ func main() { log.Fatal(err) } - // Temporary disabled - // b.AddProvider(artstation.New()) - b.AddProvider(twitter.New()) b.AddProvider(deviant.New()) diff --git a/commands/settings.go b/commands/settings.go index 03357b3..7586e54 100644 --- a/commands/settings.go +++ b/commands/settings.go @@ -153,14 +153,6 @@ func set(b *bot.Bot) func(*gumi.Ctx) error { ), ) - eb.AddField( - "ArtStation settings", - fmt.Sprintf( - "**%v**: %v", - "Status (artstation)", messages.FormatBool(guild.Artstation), - ), - ) - channels := dgoutils.Ternary(len(guild.ArtChannels) > 5, []string{"There are more than 5 art channels, use `bt!artchannels` command to see them."}, arrays.Map(guild.ArtChannels, func(s string) string { @@ -293,13 +285,6 @@ func set(b *bot.Bot) func(*gumi.Ctx) error { } guild.Deviant = applySetting(guild.Deviant, enable).(bool) - case "artstation": - enable, err := parseBool(newSetting.Raw) - if err != nil { - return err - } - - applySetting(guild.Artstation, enable) case "tags": enable, err := parseBool(newSetting.Raw) if err != nil { diff --git a/go.mod b/go.mod index 1cd8ff9..f72e39d 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,6 @@ require ( github.com/everpcpc/pixiv v0.1.2 github.com/getsentry/sentry-go v0.27.0 github.com/go-redis/redis/v8 v8.11.5 - github.com/microcosm-cc/bluemonday v1.0.26 github.com/onsi/ginkgo/v2 v2.17.1 github.com/onsi/gomega v1.33.0 github.com/servusdei2018/shards/v2 v2.4.0 @@ -26,7 +25,6 @@ require ( ) require ( - github.com/aymerick/douceur v0.2.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/dghubble/sling v1.4.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect @@ -36,7 +34,6 @@ require ( github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect - github.com/gorilla/css v1.0.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/klauspost/compress v1.17.2 // indirect github.com/montanaflynn/stats v0.7.1 // indirect diff --git a/go.sum b/go.sum index bcd4514..a41d982 100644 --- a/go.sum +++ b/go.sum @@ -6,8 +6,6 @@ github.com/VTGare/gumi v0.4.3 h1:kgk2dP20BSqagHdyETRV3b6m7u/5EWC6PJ77rybvlDE= github.com/VTGare/gumi v0.4.3/go.mod h1:rL436j8AxtY/kH/7OMpZ6AfzJ4+e0CPJnGaOXvmTNkI= github.com/VTGare/sengoku v0.1.7 h1:qRFw5cSduIYUkXS3CW5w1XwG4Qf/vZZDNBYefvsqbWc= github.com/VTGare/sengoku v0.1.7/go.mod h1:zJ6kmJNQrvLP73knCFl9hPSs/A6k812d9duax+fMLaI= -github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= -github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/bwmarrin/discordgo v0.22.0/go.mod h1:c1WtWUGN6nREDmzIpyTp/iD3VYt4Fpx+bVyfBG7JE+M= github.com/bwmarrin/discordgo v0.23.3-0.20211010150959-f0b7e81468f7/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY= github.com/bwmarrin/discordgo v0.28.1 h1:gXsuo2GBO7NbR6uqmrrBDplPUx2T3nzu775q/Rd1aG4= @@ -47,8 +45,6 @@ github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= -github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= @@ -58,8 +54,6 @@ github.com/jarcoal/httpmock v1.0.7 h1:d1a2VFpSdm5gtjhCPWsQHSnx8+5V3ms5431YwvmkuN github.com/jarcoal/httpmock v1.0.7/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58= -github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs= github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= diff --git a/messages/embeds.go b/messages/embeds.go index 256227d..f6b00dd 100644 --- a/messages/embeds.go +++ b/messages/embeds.go @@ -61,7 +61,6 @@ type SetCommand struct { PixivSettings *PixivSettings TwitterSettings *ProviderSettings DeviantSettings *ProviderSettings - ArtstationSettings *ProviderSettings ArtChannels string } @@ -152,10 +151,6 @@ var embeds = map[Language]map[EmbedType]any{ Title: "DeviantArt settings", Enabled: "Status (deviant)", }, - ArtstationSettings: &ProviderSettings{ - Title: "ArtStation settings", - Enabled: "Status (artstation)", - }, PixivSettings: &PixivSettings{ ProviderSettings: ProviderSettings{ Title: "Pixiv settings", diff --git a/post/post.go b/post/post.go index 91791b2..c2392e3 100644 --- a/post/post.go +++ b/post/post.go @@ -4,7 +4,6 @@ import ( "context" "errors" "fmt" - "github.com/VTGare/embeds" "reflect" "slices" "strconv" @@ -20,6 +19,7 @@ import ( "github.com/VTGare/boe-tea-go/messages" "github.com/VTGare/boe-tea-go/repost" "github.com/VTGare/boe-tea-go/store" + "github.com/VTGare/embeds" "github.com/VTGare/gumi" "github.com/bwmarrin/discordgo" "golang.org/x/sync/errgroup" @@ -495,7 +495,7 @@ func (p *Post) sendMessages(guild *store.Guild, channelID string, res *fetchResu for i, messages := range allMessages { for _, message := range messages { - err := sendMessage(message, res.Artworks[i].ArtworkID()) + err := sendMessage(message, res.Artworks[i].ID()) if err != nil { log.With(err).Warn("failed to send artwork message") } diff --git a/store/guilds.go b/store/guilds.go index 859f359..0b62f04 100644 --- a/store/guilds.go +++ b/store/guilds.go @@ -17,10 +17,9 @@ type Guild struct { ID string `json:"id" bson:"guild_id" validate:"required"` Prefix string `json:"prefix" bson:"prefix" validate:"required,max=5"` - Pixiv bool `json:"pixiv" bson:"pixiv"` - Twitter bool `json:"twitter" bson:"twitter"` - Deviant bool `json:"deviant" bson:"deviant"` - Artstation bool `json:"artstation" bson:"artstation"` + Pixiv bool `json:"pixiv" bson:"pixiv"` + Twitter bool `json:"twitter" bson:"twitter"` + Deviant bool `json:"deviant" bson:"deviant"` Tags bool `json:"tags" bson:"tags"` FlavorText bool `json:"flavour_text" bson:"flavour_text"` diff --git a/store/stateful.go b/store/stateful.go index 4c50f07..456d4e8 100644 --- a/store/stateful.go +++ b/store/stateful.go @@ -146,17 +146,17 @@ func (s *StatefulStore) SearchArtworks(ctx context.Context, filter ArtworkFilter sort.Slice(artworks, func(i, j int) bool { if opt.Order == Ascending { return artworks[i].Favorites < artworks[j].Favorites - } else { - return artworks[i].Favorites > artworks[j].Favorites } + + return artworks[i].Favorites > artworks[j].Favorites }) case ByTime: sort.Slice(artworks, func(i, j int) bool { if opt.Order == Ascending { return artworks[i].CreatedAt.Before(artworks[j].CreatedAt) - } else { - return artworks[i].CreatedAt.After(artworks[j].CreatedAt) } + + return artworks[i].CreatedAt.After(artworks[j].CreatedAt) }) } From 8e7f2ad6d57347ea31ea39affcf860431f29e4f5 Mon Sep 17 00:00:00 2001 From: VTGare Date: Sun, 17 Nov 2024 17:46:45 +0200 Subject: [PATCH 27/30] restore twitter matcher --- artworks/twitter/matcher.go | 9 ++++++--- artworks/twitter/twitter.go | 4 ++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/artworks/twitter/matcher.go b/artworks/twitter/matcher.go index cef5453..b83e0f3 100644 --- a/artworks/twitter/matcher.go +++ b/artworks/twitter/matcher.go @@ -2,21 +2,24 @@ package twitter import ( "net/url" + "regexp" "strconv" "strings" "github.com/VTGare/boe-tea-go/store" ) -type twitterMatcher struct{} +type twitterMatcher struct { + regex *regexp.Regexp +} -func (twitterMatcher) Match(s string) (string, bool) { +func (tm twitterMatcher) Match(s string) (string, bool) { u, err := url.ParseRequestURI(s) if err != nil { return "", false } - if !strings.Contains(u.Host, "twitter.com") && u.Host != "x.com" { + if ok := tm.regex.MatchString(u.Host); !ok { return "", false } diff --git a/artworks/twitter/twitter.go b/artworks/twitter/twitter.go index c5d4b75..29d580e 100644 --- a/artworks/twitter/twitter.go +++ b/artworks/twitter/twitter.go @@ -7,6 +7,7 @@ import ( "io" "net/http" "net/url" + "regexp" "strconv" "strings" "time" @@ -53,6 +54,9 @@ type Video struct { func New() artworks.Provider { return &Twitter{ providers: []artworks.Provider{newFxTwitter()}, + twitterMatcher: twitterMatcher{ + regex: regexp.MustCompile(`^(?:mobile\.)?(?:(?:fix(?:up|v))?x|(?:[fv]x)?twitter)\.com$`), + }, } } From 6dd68bc8c63f9b4068c87660ac3d489d0181b55b Mon Sep 17 00:00:00 2001 From: VTGare Date: Sun, 17 Nov 2024 17:48:12 +0200 Subject: [PATCH 28/30] twitter tests --- artworks/twitter/twitter_suite_test.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/artworks/twitter/twitter_suite_test.go b/artworks/twitter/twitter_suite_test.go index 5293e4b..232b6d4 100644 --- a/artworks/twitter/twitter_suite_test.go +++ b/artworks/twitter/twitter_suite_test.go @@ -24,7 +24,8 @@ var _ = DescribeTable( }, Entry("Valid artwork", "https://twitter.com/watsonameliaEN/status/1371674594675937282", "1371674594675937282", true), Entry("Query params", "https://twitter.com/watsonameliaEN/status/1371674594675937282?param=1", "1371674594675937282", true), - Entry("Mobile URL", "https://mobile.twitter.com/watsonameliaEN/status/1371674594675937282", "1371674594675937282", true), + Entry("Mobile Twitter URL", "https://mobile.twitter.com/watsonameliaEN/status/1371674594675937282", "1371674594675937282", true), + Entry("Mobile X URL", "https://mobile.x.com/watsonameliaEN/status/1371674594675937282", "1371674594675937282", true), Entry("No username", "https://twitter.com/i/status/1371674594675937282", "1371674594675937282", true), Entry("iweb URL", "https://twitter.com/i/web/status/1371674594675937282", "1371674594675937282", true), Entry("With photo suffix", "https://twitter.com/i/web/status/1371674594675937282/photo/1", "1371674594675937282", true), @@ -32,6 +33,9 @@ var _ = DescribeTable( Entry("ID with letters", "https://twitter.com/i/web/status/1371674594675937282f", "", false), Entry("Different domain", "https://google.com/i/status/123456", "", false), Entry("Invalid URL", "efe", "", false), + Entry("fxtwitter link", "https://fxtwitter.com/i/status/1234", "1234", true), Entry("vxtwitter link", "https://vxtwitter.com/i/status/1234", "1234", true), Entry("X link", "https://x.com/i/status/1234", "1234", true), + Entry("fixupx link", "https://fixupx.com/i/status/1234", "1234", true), + Entry("fixvx link", "https://fixvx.com/i/status/1234", "1234", true), ) From f2a58cb76a57c58726da588eb89dae9895420382 Mon Sep 17 00:00:00 2001 From: VTGare Date: Sun, 17 Nov 2024 18:05:32 +0200 Subject: [PATCH 29/30] fix pixiv tests --- artworks/pixiv/pixiv_suite_test.go | 2 +- go.mod | 28 +++++++-------- go.sum | 57 ++++++++++++++---------------- 3 files changed, 40 insertions(+), 47 deletions(-) diff --git a/artworks/pixiv/pixiv_suite_test.go b/artworks/pixiv/pixiv_suite_test.go index f83c033..bb8b403 100644 --- a/artworks/pixiv/pixiv_suite_test.go +++ b/artworks/pixiv/pixiv_suite_test.go @@ -16,7 +16,7 @@ func TestPixiv(t *testing.T) { var _ = DescribeTable( "Match Pixiv URL", func(url string, expectedID string, expectedResult bool) { - provider := pixiv.Pixiv{} + provider := pixiv.New("test.com") id, ok := provider.Match(url) Expect(id).To(BeEquivalentTo(expectedID)) diff --git a/go.mod b/go.mod index f72e39d..98e2705 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,8 @@ module github.com/VTGare/boe-tea-go -go 1.21 +go 1.22.0 -toolchain go1.21.0 +toolchain go1.23.1 require ( github.com/ReneKroon/ttlcache v1.7.0 @@ -13,14 +13,14 @@ require ( github.com/everpcpc/pixiv v0.1.2 github.com/getsentry/sentry-go v0.27.0 github.com/go-redis/redis/v8 v8.11.5 - github.com/onsi/ginkgo/v2 v2.17.1 - github.com/onsi/gomega v1.33.0 + github.com/onsi/ginkgo/v2 v2.21.0 + github.com/onsi/gomega v1.34.2 github.com/servusdei2018/shards/v2 v2.4.0 go.mongodb.org/mongo-driver v1.15.0 go.uber.org/atomic v1.11.0 go.uber.org/zap v1.27.0 - golang.org/x/sync v0.7.0 - golang.org/x/text v0.14.0 + golang.org/x/sync v0.8.0 + golang.org/x/text v0.19.0 mvdan.cc/xurls/v2 v2.5.0 ) @@ -28,12 +28,12 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/dghubble/sling v1.4.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect - github.com/go-logr/logr v1.4.1 // indirect - github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-querystring v1.1.0 // indirect - github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect + github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/klauspost/compress v1.17.2 // indirect github.com/montanaflynn/stats v0.7.1 // indirect @@ -47,11 +47,9 @@ require ( github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect github.com/zekroTJA/timedmap v1.5.1 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.21.0 // indirect - golang.org/x/net v0.23.0 // indirect - golang.org/x/sys v0.18.0 // indirect - golang.org/x/tools v0.17.0 // indirect + golang.org/x/crypto v0.28.0 // indirect + golang.org/x/net v0.30.0 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/tools v0.26.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) - -replace github.com/n0madic/twitter-scraper => github.com/VTGare/twitter-scraper v0.0.4 diff --git a/go.sum b/go.sum index a41d982..c000aa6 100644 --- a/go.sum +++ b/go.sum @@ -12,9 +12,6 @@ github.com/bwmarrin/discordgo v0.28.1 h1:gXsuo2GBO7NbR6uqmrrBDplPUx2T3nzu775q/Rd github.com/bwmarrin/discordgo v0.28.1/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -30,12 +27,12 @@ github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= -github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -43,13 +40,12 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/jarcoal/httpmock v1.0.7 h1:d1a2VFpSdm5gtjhCPWsQHSnx8+5V3ms5431YwvmkuNk= github.com/jarcoal/httpmock v1.0.7/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= @@ -60,10 +56,10 @@ github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8= -github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= -github.com/onsi/gomega v1.33.0 h1:snPCflnZrpMsy94p4lXVEkHo12lmPnc3vY5XBbreexE= -github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY= +github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM= +github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= +github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8= +github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= @@ -84,12 +80,12 @@ github.com/stretchr/objx v0.5.1 h1:4VhoImhV/Bm0ToFkXFi8hXNXwpDRZ/ynw3amt82mzq0= github.com/stretchr/objx v0.5.1/go.mod h1:/iHQpkQwBD6DLUmQ4pE+s1TXdob1mORJ4/UFdrifcy0= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= @@ -118,23 +114,22 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -142,25 +137,25 @@ golang.org/x/sys v0.0.0-20211015200801-69063c4bb744/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= -golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= +golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= From 26873575d2cdc0ce1a7a5238327cabcf1bc4b156 Mon Sep 17 00:00:00 2001 From: VTGare Date: Sun, 17 Nov 2024 18:18:54 +0200 Subject: [PATCH 30/30] fix typo --- handlers/handlers.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/handlers/handlers.go b/handlers/handlers.go index 6c0d44f..e1c846a 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -16,6 +16,7 @@ import ( "github.com/VTGare/boe-tea-go/internal/dgoutils" "github.com/VTGare/boe-tea-go/messages" "github.com/VTGare/boe-tea-go/post" + "github.com/VTGare/boe-tea-go/repost" "github.com/VTGare/boe-tea-go/store" "github.com/VTGare/embeds" "github.com/VTGare/gumi" @@ -155,7 +156,6 @@ func OnChannelDelete(b *bot.Bot) func(*discordgo.Session, *discordgo.ChannelDele guild.ID, []string{ch.ID}, ) - if err != nil { log.With("error", err).Warn("failed to delete art channel") } @@ -182,12 +182,9 @@ func OnMessageRemove(b *bot.Bot) func(*discordgo.Session, *discordgo.MessageDele log.With("user_id", msg.AuthorID).Info("removing children messages") for _, child := range msg.Children { - log.With("user_id", msg.AuthorID, "message_id", child.MessageID).Info("removing a respost") - + log.With("user_id", msg.AuthorID, "message_id", child.MessageID).Info("removing a repost") if err := b.RepostDetector.Delete(b.Context, child.ChannelID, child.ArtworkID); err != nil { - if strings.Contains(err.Error(), "repost not found") { - log.With("error", err) - } else { + if !errors.Is(err, repost.ErrNotFound) { log.With("error", err).Warn("failed to remove repost") } }