From c7a261205606453be23bad112a0c010efba5be2e Mon Sep 17 00:00:00 2001 From: dogghi no <75123663+doggyhaha@users.noreply.github.com> Date: Mon, 28 Apr 2025 17:23:40 +0200 Subject: [PATCH] clean code, add golangci config, preallocate some slices and avoid copying body before parsing json (#9) --- .gitignore | 1 + .golangci.yml | 19 +++++++++++++++++++ bot/core/default.go | 2 +- bot/core/util.go | 4 ++-- ext/instagram/main.go | 2 +- ext/instagram/util.go | 41 +++++++++++++++-------------------------- ext/ninegag/util.go | 3 ++- ext/pinterest/util.go | 1 + ext/tiktok/main.go | 2 +- ext/twitter/main.go | 10 +++------- models/media.go | 2 +- util/edgeproxy.go | 7 ++----- 12 files changed, 49 insertions(+), 45 deletions(-) create mode 100644 .golangci.yml diff --git a/.gitignore b/.gitignore index 98667ef..bdcc74c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ main_test.go old/ +bin/ .env ext-cfg.yaml diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..f4cdd62 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,19 @@ +run: + timeout: 5m + +linters: + enable: + - bodyclose + - gocritic + - unconvert + - ineffassign + - staticcheck + - prealloc + - nilerr + - gosimple + - asasalint + disable: + - errcheck + +issues: + exclude-use-default: false diff --git a/bot/core/default.go b/bot/core/default.go index 9246d41..51a9b2f 100644 --- a/bot/core/default.go +++ b/bot/core/default.go @@ -114,7 +114,7 @@ func HandleDefaultStoredFormatDownload( storedMedias[0], isCaptionEnabled, ) - var medias []*models.DownloadedMedia + medias := make([]*models.DownloadedMedia, 0, len(storedMedias)) for _, media := range storedMedias { medias = append(medias, &models.DownloadedMedia{ FilePath: "", diff --git a/bot/core/util.go b/bot/core/util.go index eb88493..3d6b7bb 100644 --- a/bot/core/util.go +++ b/bot/core/util.go @@ -103,12 +103,12 @@ func StoreMedias( msgs []gotgbot.Message, medias []*models.DownloadedMedia, ) error { - var storedMedias []*models.Media - if len(medias) == 0 { return errors.New("no media to store") } + storedMedias := make([]*models.Media, 0, len(medias)) + for idx, msg := range msgs { fileID := GetMessageFileID(&msg) if len(fileID) == 0 { diff --git a/ext/instagram/main.go b/ext/instagram/main.go index aa08338..818d281 100644 --- a/ext/instagram/main.go +++ b/ext/instagram/main.go @@ -137,12 +137,12 @@ func GetEmbedMediaList( } func GetIGramMediaList(ctx *models.DownloadContext) ([]*models.Media, error) { - var mediaList []*models.Media postURL := ctx.MatchedContentURL details, err := GetFromIGram(ctx, postURL) if err != nil { return nil, fmt.Errorf("failed to get post: %w", err) } + mediaList := make([]*models.Media, 0, len(details.Items)) for _, item := range details.Items { media := ctx.Extractor.NewMedia( ctx.MatchedContentID, diff --git a/ext/instagram/util.go b/ext/instagram/util.go index 7cd9abd..5342bf6 100644 --- a/ext/instagram/util.go +++ b/ext/instagram/util.go @@ -1,6 +1,7 @@ package instagram import ( + "bytes" "crypto/rand" "crypto/sha256" "encoding/hex" @@ -137,14 +138,14 @@ func ParseGQLMedia( func ParseEmbedGQL( body []byte, ) (*Media, error) { - match := embedPattern.FindStringSubmatch(string(body)) + match := embedPattern.FindSubmatch(body) if len(match) < 2 { return nil, errors.New("failed to find JSON in response") } jsonData := match[1] var data map[string]any - if err := json5.Unmarshal([]byte(jsonData), &data); err != nil { + if err := json5.Unmarshal(jsonData, &data); err != nil { return nil, fmt.Errorf("failed to unmarshal JSON: %w", err) } igCtx := util.TraverseJSON(data, "contextJSON") @@ -193,39 +194,27 @@ func BuildIGramPayload(contentURL string) (io.Reader, error) { if err != nil { return nil, fmt.Errorf("error marshalling payload: %w", err) } - reader := strings.NewReader(string(parsedPayload)) + reader := bytes.NewReader(parsedPayload) return reader, nil } func ParseIGramResponse(body []byte) (*IGramResponse, error) { - var rawResponse any + // try to unmarshal as a single IGramMedia and then as a slice + var media IGramMedia - if err := sonic.ConfigFastest.Unmarshal(body, &rawResponse); err != nil { - return nil, fmt.Errorf("failed to decode response1: %w", err) - } - - switch rawResponse.(type) { - case []any: - // array of IGramMedia - var media []*IGramMedia - if err := sonic.ConfigFastest.Unmarshal(body, &media); err != nil { - return nil, fmt.Errorf("failed to decode response2: %w", err) + if err := sonic.ConfigFastest.Unmarshal(body, &media); err != nil { + // try with slice + var mediaList []*IGramMedia + if err := sonic.ConfigFastest.Unmarshal(body, &mediaList); err != nil { + return nil, fmt.Errorf("failed to decode response: %w", err) } return &IGramResponse{ - Items: media, + Items: mediaList, }, nil - case map[string]any: - // single IGramMedia - var media IGramMedia - if err := sonic.ConfigFastest.Unmarshal(body, &media); err != nil { - return nil, fmt.Errorf("failed to decode response3: %w", err) } - return &IGramResponse{ - Items: []*IGramMedia{&media}, - }, nil - default: - return nil, fmt.Errorf("unexpected response type: %T", rawResponse) - } + return &IGramResponse{ + Items: []*IGramMedia{&media}, + }, nil } func GetCDNURL(contentURL string) (string, error) { diff --git a/ext/ninegag/util.go b/ext/ninegag/util.go index 755ccc0..08be524 100644 --- a/ext/ninegag/util.go +++ b/ext/ninegag/util.go @@ -36,7 +36,6 @@ func FindBestPhoto( func ParseVideoFormats( images map[string]*Media, ) ([]*models.MediaFormat, error) { - var formats []*models.MediaFormat var video *Media var thumbnailURL string @@ -63,6 +62,8 @@ func ParseVideoFormats( "av1Url": {"Av1URL", enums.MediaCodecAV1}, } + formats := make([]*models.MediaFormat, 0, len(codecMapping)) + for _, mapping := range codecMapping { url := getField(video, mapping.Field) if url == "" { diff --git a/ext/pinterest/util.go b/ext/pinterest/util.go index 9359186..90ec067 100644 --- a/ext/pinterest/util.go +++ b/ext/pinterest/util.go @@ -31,6 +31,7 @@ func ParseVideoObject(videoObj *Videos) ([]*models.MediaFormat, error) { if err != nil { return nil, fmt.Errorf("failed to extract hls formats: %w", err) } + formats = make([]*models.MediaFormat, 0, len(hlsFormats)) for _, hlsFormat := range hlsFormats { hlsFormat.Duration = video.Duration / 1000 hlsFormat.Thumbnail = []string{video.Thumbnail} diff --git a/ext/tiktok/main.go b/ext/tiktok/main.go index e269a52..996ada3 100644 --- a/ext/tiktok/main.go +++ b/ext/tiktok/main.go @@ -176,7 +176,7 @@ func GetVideoAPI( decoder := sonic.ConfigFastest.NewDecoder(resp.Body) err = decoder.Decode(&data) if err != nil { - return nil, fmt.Errorf("failed to unmarshal response: %w", err) + return nil, fmt.Errorf("failed to decode response: %w", err) } videoData, err := FindVideoData(data, awemeID) if err != nil { diff --git a/ext/twitter/main.go b/ext/twitter/main.go index 9b1fdbd..73e3c7e 100644 --- a/ext/twitter/main.go +++ b/ext/twitter/main.go @@ -45,12 +45,12 @@ var ShortExtractor = &models.Extractor{ if err != nil { return nil, fmt.Errorf("failed to read body: %w", err) } - matchedURL := Extractor.URLPattern.FindStringSubmatch(string(body)) + matchedURL := Extractor.URLPattern.FindSubmatch(body) if matchedURL == nil { return nil, errors.New("failed to find url in body") } return &models.ExtractorResponse{ - URL: matchedURL[0], + URL: string(matchedURL[0]), }, nil }, } @@ -174,13 +174,9 @@ func GetTweetAPI( if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("invalid response code: %s", resp.Status) } - body, err := io.ReadAll(resp.Body) - if err != nil { - return nil, fmt.Errorf("failed to read body: %w", err) - } var apiResponse APIResponse - err = sonic.ConfigFastest.Unmarshal(body, &apiResponse) + err = sonic.ConfigFastest.NewDecoder(resp.Body).Decode(&apiResponse) if err != nil { return nil, fmt.Errorf("failed to parse response: %w", err) } diff --git a/models/media.go b/models/media.go index 83a338d..32db32f 100644 --- a/models/media.go +++ b/models/media.go @@ -246,7 +246,7 @@ func (media *Media) GetSortedFormats() []*MediaFormat { } // combine the best video and audio into a final list - var finalSortedList []*MediaFormat + finalSortedList := make([]*MediaFormat, 0, len(groupedVideos)+len(groupedAudios)+len(media.Formats)) for _, best := range groupedVideos { finalSortedList = append(finalSortedList, best) } diff --git a/util/edgeproxy.go b/util/edgeproxy.go index 70ec9af..ca132dd 100644 --- a/util/edgeproxy.go +++ b/util/edgeproxy.go @@ -107,13 +107,10 @@ func copyHeaders(source, destination http.Header) { } func parseProxyResponse(proxyResp *http.Response, originalReq *http.Request) (*http.Response, error) { - body, err := io.ReadAll(proxyResp.Body) - if err != nil { - return nil, fmt.Errorf("error reading proxy response: %w", err) - } var response models.EdgeProxyResponse - if err := sonic.ConfigFastest.Unmarshal(body, &response); err != nil { + decoder := sonic.ConfigFastest.NewDecoder(proxyResp.Body) + if err := decoder.Decode(&response); err != nil { return nil, fmt.Errorf("error parsing proxy response: %w", err) }