diff --git a/internal/deezer/client.go b/internal/deezer/client.go index a5b8a95..c1a3c13 100644 --- a/internal/deezer/client.go +++ b/internal/deezer/client.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "encoding/json" + "errors" "fmt" "io" "net/http" @@ -62,7 +63,7 @@ func (c *Client) FetchResource(ctx context.Context, kind Kind, id string) (Resou return nil, err } - payload := map[string]interface{}{ + payload := map[string]any{ "nb": 10000, "start": 0, "lang": "en", @@ -78,7 +79,7 @@ func (c *Client) FetchResource(ctx context.Context, kind Kind, id string) (Resou } url := fmt.Sprintf("https://www.deezer.com/ajax/gw-light.php?method=deezer.page%s&input=3&api_version=1.0&api_token=%s", kind.pageMethod(), c.Session.APIToken) - req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(jsonData)) + req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewBuffer(jsonData)) if err != nil { return nil, err } @@ -109,12 +110,12 @@ func (c *Client) FetchResource(ctx context.Context, kind Kind, id string) (Resou {`"DATA_ERROR":"song::getData"`, "invalid track ID"}, } { if strings.Contains(bodyStr, check.marker) { - return nil, fmt.Errorf("%s", check.errMsg) + return nil, errors.New(check.errMsg) } } if strings.Contains(bodyStr, `"results":{}`) { - return nil, fmt.Errorf("unexpected response") + return nil, errors.New("unexpected response") } if err := resource.decode(body); err != nil { @@ -132,7 +133,7 @@ func (c *Client) FetchMedia(ctx context.Context, track *Track, quality string) ( } reqBody := fmt.Sprintf(`{"license_token":"%s","media":[{"type":"FULL","formats":%s}],"track_tokens":["%s"]}`, c.Session.LicenseToken, qualityFormats[quality], track.TrackToken) - req, err := http.NewRequestWithContext(ctx, "POST", "https://media.deezer.com/v1/get_url", bytes.NewBuffer([]byte(reqBody))) + req, err := http.NewRequestWithContext(ctx, http.MethodPost, "https://media.deezer.com/v1/get_url", bytes.NewBuffer([]byte(reqBody))) if err != nil { return nil, err } @@ -159,20 +160,20 @@ func (c *Client) FetchMedia(ctx context.Context, track *Track, quality string) ( if len(media.Errors) > 0 { if media.Errors[0].Code == 1000 { - return nil, fmt.Errorf("invalid license token") + return nil, errors.New("invalid license token") } - return nil, fmt.Errorf("%s", media.Errors[0].Message) + return nil, errors.New(media.Errors[0].Message) } if len(media.Data) > 0 && len(media.Data[0].Errors) > 0 { if media.Data[0].Errors[0].Code == 2002 { - return nil, fmt.Errorf("invalid track token") + return nil, errors.New("invalid track token") } - return nil, fmt.Errorf("%s", media.Data[0].Errors[0].Message) + return nil, errors.New(media.Data[0].Errors[0].Message) } if len(media.Data) == 0 || len(media.Data[0].Media) == 0 || len(media.Data[0].Media[0].Sources) == 0 { - return nil, fmt.Errorf("no sources found") + return nil, errors.New("no sources found") } return &media, nil @@ -180,7 +181,7 @@ func (c *Client) FetchMedia(ctx context.Context, track *Track, quality string) ( func (c *Client) FetchCoverImage(ctx context.Context, track *Track) ([]byte, error) { url := fmt.Sprintf("https://e-cdn-images.dzcdn.net/images/cover/%s/500x500-000000-80-0-0.jpg", track.Cover) - req, err := http.NewRequestWithContext(ctx, "GET", url, nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return nil, err } @@ -199,7 +200,7 @@ func (c *Client) FetchCoverImage(ctx context.Context, track *Track) ([]byte, err } func (c *Client) MediaStream(ctx context.Context, media *Media) (io.ReadCloser, error) { - req, err := http.NewRequestWithContext(ctx, "GET", media.URL(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, media.URL(), nil) if err != nil { return nil, err } diff --git a/internal/deezer/gateway.go b/internal/deezer/gateway.go index 62451c7..71a7787 100644 --- a/internal/deezer/gateway.go +++ b/internal/deezer/gateway.go @@ -6,6 +6,7 @@ import ( "crypto/aes" "encoding/hex" "encoding/json" + "errors" "fmt" "io" "math/rand/v2" @@ -47,7 +48,7 @@ func gatewayEnv() (string, string, error) { apiKey := os.Getenv("DEEZER_MOBILE_API_KEY") gwKey := os.Getenv("DEEZER_MOBILE_GW_KEY") if apiKey == "" || gwKey == "" { - return "", "", fmt.Errorf("DEEZER_MOBILE_API_KEY and DEEZER_MOBILE_GW_KEY must be set to use email/password login") + return "", "", errors.New("DEEZER_MOBILE_API_KEY and DEEZER_MOBILE_GW_KEY must be set to use email/password login") } if len(gwKey) != aes.BlockSize { @@ -89,7 +90,7 @@ func (m *mobileClient) login(ctx context.Context, email, password string) (*Cred } func (m *mobileClient) authenticate(ctx context.Context) (string, string, string, error) { - body, err := m.gatewayRequest(ctx, "mobile_auth", "GET", "uniq_id", genUniqID(), nil) + body, err := m.gatewayRequest(ctx, "mobile_auth", http.MethodGet, "uniq_id", genUniqID(), nil) if err != nil { return "", "", "", err } @@ -104,10 +105,10 @@ func (m *mobileClient) authenticate(ctx context.Context) (string, string, string } if strings.Contains(string(body), "Undefined or invalid API key") { - return "", "", "", fmt.Errorf("DEEZER_MOBILE_API_KEY is invalid") + return "", "", "", errors.New("DEEZER_MOBILE_API_KEY is invalid") } if strings.Contains(string(body), "GATEWAY_ERROR") || res.Results.Token == "" { - return "", "", "", fmt.Errorf("unexpected response from gateway") + return "", "", "", errors.New("unexpected response from gateway") } encrypted, err := hex.DecodeString(res.Results.Token) @@ -121,7 +122,7 @@ func (m *mobileClient) authenticate(ctx context.Context) (string, string, string } if len(decrypted) < 96 { - return "", "", "", fmt.Errorf("unexpected response from gateway") + return "", "", "", errors.New("unexpected response from gateway") } token := string(decrypted[0:64]) @@ -138,7 +139,7 @@ func (m *mobileClient) checkToken(ctx context.Context, token, tokenKey string) e } authToken := hex.EncodeToString(encrypted) - body, err := m.gatewayRequest(ctx, "api_checkToken", "GET", "auth_token", authToken, nil) + body, err := m.gatewayRequest(ctx, "api_checkToken", http.MethodGet, "auth_token", authToken, nil) if err != nil { return err } @@ -150,7 +151,7 @@ func (m *mobileClient) checkToken(ctx context.Context, token, tokenKey string) e return err } if res.Results == "" { - return fmt.Errorf("unexpected response from gateway") + return errors.New("unexpected response from gateway") } m.sid = res.Results @@ -183,13 +184,13 @@ func (m *mobileClient) userAuth(ctx context.Context, email, password, userKey st return "", "", err } - body, err := m.gatewayRequest(ctx, "mobile_userAuth", "POST", "", "", jsonBody) + body, err := m.gatewayRequest(ctx, "mobile_userAuth", http.MethodPost, "", "", jsonBody) if err != nil { return "", "", err } if strings.Contains(string(body), "USER_AUTH_ERROR") { - return "", "", fmt.Errorf("invalid email or password") + return "", "", errors.New("invalid email or password") } var res struct { @@ -204,7 +205,7 @@ func (m *mobileClient) userAuth(ctx context.Context, email, password, userKey st } if res.Results.ARL == "" || res.Results.UserID == 0 { - return "", "", fmt.Errorf("unexpected response from gateway") + return "", "", errors.New("unexpected response from gateway") } return res.Results.ARL, res.Results.BlogName, nil @@ -220,7 +221,7 @@ func (m *mobileClient) gatewayRequest(ctx context.Context, method, httpMethod, p q.Set("method", method) q.Set("api_key", m.apiKey) q.Set("output", "3") - if httpMethod == "POST" { + if httpMethod == http.MethodPost { q.Set("input", "3") } if m.sid != "" { diff --git a/internal/deezer/login.go b/internal/deezer/login.go index 7237789..c6685d8 100644 --- a/internal/deezer/login.go +++ b/internal/deezer/login.go @@ -32,7 +32,7 @@ func resolveARL(ctx context.Context, validate func(ctx context.Context, arl stri return arl, nil } - return "", fmt.Errorf("run 'godeez login' or export DEEZER_ARL environment variable") + return "", errors.New("run 'godeez login' or export DEEZER_ARL environment variable") } func Login(ctx context.Context, email, password string) (string, string, error) { diff --git a/internal/deezer/session.go b/internal/deezer/session.go index ba535bf..c1c41df 100644 --- a/internal/deezer/session.go +++ b/internal/deezer/session.go @@ -31,7 +31,7 @@ func authenticate(ctx context.Context, arlCookie string) (*Session, error) { } url := "https://www.deezer.com/ajax/gw-light.php?method=deezer.getUserData&input=3&api_version=1.0&api_token=" - req, err := http.NewRequestWithContext(ctx, "GET", url, nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return nil, err } diff --git a/internal/download/bpm.go b/internal/download/bpm.go index cb0cfc1..30c2ed7 100644 --- a/internal/download/bpm.go +++ b/internal/download/bpm.go @@ -3,6 +3,7 @@ package download import ( "bytes" "context" + "errors" "fmt" "io" "net/http" @@ -40,7 +41,7 @@ func findTrackURL(ctx context.Context, httpClient *http.Client, artist, title, d values := neturl.Values{} values.Add("query", fmt.Sprintf("%s %s", artist, title)) - req, err := http.NewRequestWithContext(ctx, "POST", rootURL+"/searches", bytes.NewBufferString(values.Encode())) + req, err := http.NewRequestWithContext(ctx, http.MethodPost, rootURL+"/searches", bytes.NewBufferString(values.Encode())) if err != nil { return "", err } @@ -102,14 +103,14 @@ func findTrackURL(ctx context.Context, httpClient *http.Client, artist, title, d }) if matchURL == "" { - return "", fmt.Errorf("no data found") + return "", errors.New("no data found") } return rootURL + matchURL, nil } func fetchBPMPage(ctx context.Context, httpClient *http.Client, url string) (string, error) { - req, err := http.NewRequestWithContext(ctx, "GET", url, nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return "", err } @@ -138,7 +139,7 @@ func parseBPM(html string) (bpmKey, error) { modeMatch := modeRegex.FindStringSubmatch(html) if len(bpmMatch) != 2 || len(keyMatch) != 2 || len(modeMatch) != 2 { - return bpmKey{}, fmt.Errorf("no data found") + return bpmKey{}, errors.New("no data found") } bpm := bpmMatch[1] diff --git a/internal/download/genre.go b/internal/download/genre.go index a3ab6bc..421c860 100644 --- a/internal/download/genre.go +++ b/internal/download/genre.go @@ -2,6 +2,7 @@ package download import ( "context" + "errors" "fmt" "net/http" "net/url" @@ -50,14 +51,14 @@ func fetchGenre(ctx context.Context, httpClient *http.Client, artist, title stri filtered := filterTags(tags) if len(filtered) == 0 { - return "", fmt.Errorf("no data found") + return "", errors.New("no data found") } return formatTags(filtered), nil } func fetchGenrePage(ctx context.Context, httpClient *http.Client, url string) (*goquery.Document, error) { - req, err := http.NewRequestWithContext(ctx, "GET", url, nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return nil, err } diff --git a/internal/download/options.go b/internal/download/options.go index 1355354..881d79c 100644 --- a/internal/download/options.go +++ b/internal/download/options.go @@ -1,6 +1,7 @@ package download import ( + "errors" "fmt" "time" @@ -27,14 +28,14 @@ func (o *Options) Validate(kind deezer.Kind) error { return fmt.Errorf("invalid quality option: %s", o.Quality) } if o.Timeout <= 0 { - return fmt.Errorf("timeout must be a positive duration") + return errors.New("timeout must be a positive duration") } if kind == deezer.KindArtist { if o.Limit <= 0 { - return fmt.Errorf("limit must be a positive integer") + return errors.New("limit must be a positive integer") } if o.Limit > 100 { - return fmt.Errorf("limit must not exceed 100") + return errors.New("limit must not exceed 100") } } diff --git a/internal/download/progress.go b/internal/download/progress.go index efd2a3a..aea9985 100644 --- a/internal/download/progress.go +++ b/internal/download/progress.go @@ -2,7 +2,7 @@ package download import ( "fmt" - "math/rand" + "math/rand/v2" "os" "time" diff --git a/internal/store/download_info.go b/internal/store/download_info.go index a512969..40246ee 100644 --- a/internal/store/download_info.go +++ b/internal/store/download_info.go @@ -2,6 +2,7 @@ package store import ( "encoding/json" + "errors" "fmt" "time" @@ -24,12 +25,12 @@ func (s *Store) DownloadInfo(trackID string) (*DownloadInfo, error) { if err := s.db.View(func(tx *bbolt.Tx) error { b := tx.Bucket(trackBucket) if b == nil { - return fmt.Errorf("bucket not found") + return errors.New("bucket not found") } data := b.Get([]byte(trackID)) if data == nil { - return fmt.Errorf("not found") + return errors.New("not found") } return json.Unmarshal(data, &info) }); err != nil { diff --git a/internal/store/store.go b/internal/store/store.go index 71ce365..c110ec7 100644 --- a/internal/store/store.go +++ b/internal/store/store.go @@ -6,19 +6,19 @@ import ( "path/filepath" "time" - bolt "go.etcd.io/bbolt" + "go.etcd.io/bbolt" bolterrors "go.etcd.io/bbolt/errors" ) type Store struct { - db *bolt.DB + db *bbolt.DB } func Open(dir string) (*Store, error) { - db, err := bolt.Open(filepath.Join(dir, ".tracks.db"), 0600, &bolt.Options{Timeout: 5 * time.Second}) + db, err := bbolt.Open(filepath.Join(dir, ".tracks.db"), 0600, &bbolt.Options{Timeout: 5 * time.Second}) if err != nil { if errors.Is(err, bolterrors.ErrTimeout) { - return nil, fmt.Errorf("database is already in use by another process") + return nil, errors.New("database is already in use by another process") } return nil, fmt.Errorf("failed to open database: %w", err) } diff --git a/internal/tag/id3v2.go b/internal/tag/id3v2.go index 5ff22b9..0ef34c0 100644 --- a/internal/tag/id3v2.go +++ b/internal/tag/id3v2.go @@ -1,7 +1,6 @@ package tag import ( - "fmt" "strconv" "strings" @@ -37,7 +36,7 @@ func (t *id3v2Tagger) write(m Metadata) error { t.addTag("TEXT", m.Lyricists) t.addTag("TCON", m.Genre) if duration, err := strconv.Atoi(m.Duration); err == nil { - t.addTag("TLEN", fmt.Sprintf("%d", duration*1000)) + t.addTag("TLEN", strconv.Itoa(duration*1000)) } t.addTag("TBPM", m.BPM) t.addTag("TKEY", m.Key) diff --git a/internal/update/release.go b/internal/update/release.go index 93729b7..0bec2b9 100644 --- a/internal/update/release.go +++ b/internal/update/release.go @@ -3,6 +3,7 @@ package update import ( "context" "encoding/json" + "errors" "fmt" "io" "runtime" @@ -46,7 +47,7 @@ func (u *Updater) Latest(ctx context.Context) (*Release, error) { return nil, fmt.Errorf("failed to decode release: %w", err) } if release.TagName == "" { - return nil, fmt.Errorf("release has no tag name") + return nil, errors.New("release has no tag name") } return &release, nil