diff --git a/butlerd/generous/docs/README.md b/butlerd/generous/docs/README.md
index 4f169836..bd450935 100644
--- a/butlerd/generous/docs/README.md
+++ b/butlerd/generous/docs/README.md
@@ -1948,6 +1948,86 @@ afterwards with ‘Fresh’ set
+### Fetch.UploadBuilds (client request)
+
+
+
+
Fetch.UploadBuilds (client request) (Go to definition)
+
+
+
Fetches builds for an itch.io game
+
+
+
+
+
+game |
+Game |
+
+
+upload |
+Upload |
+
+
+
+
+
+
+
+
FetchUploadBuilds (Go to definition)
+
+
+
+
+
+
### Fetch.User (client request)
diff --git a/butlerd/generous/spec/butlerd.json b/butlerd/generous/spec/butlerd.json
index 100ffc37..5ea46a42 100644
--- a/butlerd/generous/spec/butlerd.json
+++ b/butlerd/generous/spec/butlerd.json
@@ -616,6 +616,34 @@
]
}
},
+ {
+ "method": "Fetch.UploadBuilds",
+ "doc": "Fetches builds for an itch.io game",
+ "caller": "client",
+ "params": {
+ "fields": [
+ {
+ "name": "game",
+ "doc": "Game whose builds we should look for",
+ "type": "Game"
+ },
+ {
+ "name": "upload",
+ "doc": "Upload whose builds we should look for",
+ "type": "Upload"
+ }
+ ]
+ },
+ "result": {
+ "fields": [
+ {
+ "name": "builds",
+ "doc": "List of builds",
+ "type": "Build[]"
+ }
+ ]
+ }
+ },
{
"method": "Fetch.User",
"doc": "Fetches information for an itch.io user.",
diff --git a/butlerd/messages/messages.go b/butlerd/messages/messages.go
index 72f567d8..e061a464 100644
--- a/butlerd/messages/messages.go
+++ b/butlerd/messages/messages.go
@@ -1152,6 +1152,46 @@ func (r *FetchGameUploadsType) TestCall(rc *butlerd.RequestContext, params butle
var FetchGameUploads *FetchGameUploadsType
+// Fetch.UploadBuilds (Request)
+
+type FetchUploadBuildsType struct {}
+
+var _ RequestMessage = (*FetchUploadBuildsType)(nil)
+
+func (r *FetchUploadBuildsType) Method() string {
+ return "Fetch.UploadBuilds"
+}
+
+func (r *FetchUploadBuildsType) Register(router router, f func(*butlerd.RequestContext, butlerd.FetchUploadBuildsParams) (*butlerd.FetchUploadBuildsResult, error)) {
+ router.Register("Fetch.UploadBuilds", func (rc *butlerd.RequestContext) (interface{}, error) {
+ var params butlerd.FetchUploadBuildsParams
+ err := json.Unmarshal(*rc.Params, ¶ms)
+ if err != nil {
+ return nil, &butlerd.RpcError{Code: jsonrpc2.CodeParseError, Message: err.Error()}
+ }
+ err = params.Validate()
+ if err != nil {
+ return nil, err
+ }
+ res, err := f(rc, params)
+ if err != nil {
+ return nil, err
+ }
+ if res == nil {
+ return nil, errors.New("internal error: nil result for Fetch.UploadBuilds")
+ }
+ return res, nil
+ })
+}
+
+func (r *FetchUploadBuildsType) TestCall(rc *butlerd.RequestContext, params butlerd.FetchUploadBuildsParams) (*butlerd.FetchUploadBuildsResult, error) {
+ var result butlerd.FetchUploadBuildsResult
+ err := rc.Call("Fetch.UploadBuilds", params, &result)
+ return &result, err
+}
+
+var FetchUploadBuilds *FetchUploadBuildsType
+
// Fetch.User (Request)
type FetchUserType struct {}
@@ -3544,6 +3584,7 @@ func EnsureAllRequests(router *butlerd.Router) {
if _, ok := router.Handlers["Fetch.DownloadKey"]; !ok { panic("missing request handler for (Fetch.DownloadKey)") }
if _, ok := router.Handlers["Fetch.DownloadKeys"]; !ok { panic("missing request handler for (Fetch.DownloadKeys)") }
if _, ok := router.Handlers["Fetch.GameUploads"]; !ok { panic("missing request handler for (Fetch.GameUploads)") }
+ if _, ok := router.Handlers["Fetch.UploadBuilds"]; !ok { panic("missing request handler for (Fetch.UploadBuilds)") }
if _, ok := router.Handlers["Fetch.User"]; !ok { panic("missing request handler for (Fetch.User)") }
if _, ok := router.Handlers["Fetch.Sale"]; !ok { panic("missing request handler for (Fetch.Sale)") }
if _, ok := router.Handlers["Fetch.Collection"]; !ok { panic("missing request handler for (Fetch.Collection)") }
diff --git a/butlerd/types.go b/butlerd/types.go
index 134e463a..e36adbdd 100644
--- a/butlerd/types.go
+++ b/butlerd/types.go
@@ -715,6 +715,31 @@ func (r *FetchGameUploadsResult) SetStale(stale bool) {
r.Stale = stale
}
+// Fetches builds for an itch.io game
+//
+// @name Fetch.UploadBuilds
+// @category Fetch
+// @caller client
+type FetchUploadBuildsParams struct {
+ // Game whose builds we should look for
+ Game *itchio.Game `json:"game"`
+
+ // Upload whose builds we should look for
+ Upload *itchio.Upload `json:"upload"`
+}
+
+func (p FetchUploadBuildsParams) Validate() error {
+ return validation.ValidateStruct(&p,
+ validation.Field(&p.Game, validation.Required),
+ validation.Field(&p.Upload, validation.Required),
+ )
+}
+
+type FetchUploadBuildsResult struct {
+ // List of builds
+ Builds []*itchio.Build `json:"builds"`
+}
+
// Fetches information for an itch.io user.
//
// @name Fetch.User
diff --git a/endpoints/fetch/fetch.go b/endpoints/fetch/fetch.go
index eda5ede6..ce70b8bb 100644
--- a/endpoints/fetch/fetch.go
+++ b/endpoints/fetch/fetch.go
@@ -8,6 +8,7 @@ import (
func Register(router *butlerd.Router) {
messages.FetchGame.Register(router, FetchGame)
messages.FetchGameUploads.Register(router, FetchGameUploads)
+ messages.FetchUploadBuilds.Register(router, FetchUploadBuilds)
messages.FetchUser.Register(router, FetchUser)
messages.FetchSale.Register(router, FetchSale)
messages.FetchCollection.Register(router, FetchCollection)
diff --git a/endpoints/fetch/fetch_upload_builds.go b/endpoints/fetch/fetch_upload_builds.go
new file mode 100644
index 00000000..fb614f66
--- /dev/null
+++ b/endpoints/fetch/fetch_upload_builds.go
@@ -0,0 +1,31 @@
+package fetch
+
+import (
+ "crawshaw.io/sqlite"
+ "github.com/itchio/butler/butlerd"
+ "github.com/itchio/butler/cmd/operate"
+ "github.com/itchio/go-itchio"
+ "github.com/pkg/errors"
+)
+
+func FetchUploadBuilds(rc *butlerd.RequestContext, params butlerd.FetchUploadBuildsParams) (*butlerd.FetchUploadBuildsResult, error) {
+ res := &butlerd.FetchUploadBuildsResult{}
+
+ var access *operate.GameAccess
+ rc.WithConn(func(conn *sqlite.Conn) {
+ access = operate.AccessForGameID(conn, params.Game.ID)
+ })
+ client := rc.Client(access.APIKey)
+
+ buildsRes, err := client.ListUploadBuilds(rc.Ctx, itchio.ListUploadBuildsParams{
+ UploadID: params.Upload.ID,
+ Credentials: access.Credentials,
+ })
+ if err != nil {
+ return nil, errors.WithStack(err)
+ }
+
+ res.Builds = buildsRes.Builds
+
+ return res, nil
+}