diff options
| author | hachem <im@hachem.wtf> | 2026-08-29 03:29:51 +0200 |
|---|---|---|
| committer | hachem <im@hachem.wtf> | 2026-08-29 03:29:51 +0200 |
| commit | a221b4c5edd3ff4d4a9d74113d9d3b8c7473133d (patch) | |
| tree | d902da32c84dad3d5fe0152be07d3bea6d4f9ee1 /internal/modrinth | |
| parent | f60177934a18daea3b24a37cf109bb2c7bfaaa72 (diff) | |
add: modrinth client and check command
Diffstat (limited to 'internal/modrinth')
| -rw-r--r-- | internal/modrinth/modrinth.go | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/internal/modrinth/modrinth.go b/internal/modrinth/modrinth.go new file mode 100644 index 0000000..8060f3b --- /dev/null +++ b/internal/modrinth/modrinth.go @@ -0,0 +1,128 @@ +package modrinth + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "os" + "time" +) + +const ( + apiBase = "https://api.modrinth.com/v2" + userAgent = "benson/2.0 (github.com/hachem-wtf/benson)" +) + +type File struct { + URL string `json:"url"` + Filename string `json:"filename"` + Primary bool `json:"primary"` +} + +type Version struct { + ID string `json:"id"` + VersionNumber string `json:"version_number"` + DatePublished time.Time `json:"date_published"` + GameVersions []string `json:"game_versions"` + Loaders []string `json:"loaders"` + Files []File `json:"files"` +} + +type Client struct { + http *http.Client +} + +func NewClient() *Client { + return &Client{http: &http.Client{Timeout: 30 * time.Second}} +} + +func (c *Client) GetVersions(slug string) ([]Version, error) { + url := fmt.Sprintf("%s/project/%s/version", apiBase, slug) + + req, err := http.NewRequest(http.MethodGet, url, nil) + if err != nil { + return nil, err + } + req.Header.Set("User-Agent", userAgent) + + resp, err := c.http.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("modrinth: %s returned %s", slug, resp.Status) + } + + var versions []Version + if err := json.NewDecoder(resp.Body).Decode(&versions); err != nil { + return nil, err + } + return versions, nil +} + +func LatestVersion(versions []Version) *Version { + if len(versions) == 0 { + return nil + } + + best := 0 + for i := 1; i < len(versions); i++ { + if versions[i].DatePublished.After(versions[best].DatePublished) { + best = i + } + } + return &versions[best] +} + +func CompatibleVersion(versions []Version, mcVersion, loader string) *Version { + var compatible []Version + for _, v := range versions { + if !contains(v.GameVersions, mcVersion) { + continue + } + if loader != "" && !contains(v.Loaders, loader) { + continue + } + compatible = append(compatible, v) + } + return LatestVersion(compatible) +} + +func (c *Client) Download(url, dest string) error { + req, err := http.NewRequest(http.MethodGet, url, nil) + if err != nil { + return err + } + req.Header.Set("User-Agent", userAgent) + + resp, err := c.http.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("download: %s returned %s", url, resp.Status) + } + + f, err := os.Create(dest) + if err != nil { + return err + } + defer f.Close() + + _, err = io.Copy(f, resp.Body) + return err +} + +func contains(list []string, s string) bool { + for _, item := range list { + if item == s { + return true + } + } + return false +} |
