feat(collections): add support for collections

This commit is contained in:
2022-12-11 20:55:18 +00:00
parent b26150c6a1
commit 7b1d0a0376
5 changed files with 253 additions and 0 deletions

View File

@@ -19,6 +19,7 @@ var (
ErrInvalidAuthToken = fmt.Errorf("%w: invalid auth token", Err)
ErrInvalidAPIURL = fmt.Errorf("%w: invalid API URL", Err)
ErrInvalidHTTPClient = fmt.Errorf("%w: invalid HTTP client", Err)
ErrNotFound = fmt.Errorf("%w: not found", Err)
ErrResponse = fmt.Errorf("%w: response", Err)
ErrResponseStatus = fmt.Errorf("%w: response status", ErrResponse)

56
collection_data.go Normal file
View File

@@ -0,0 +1,56 @@
package midjourney
import "context"
type CollectionData struct {
Filters *CollectionFilters `json:"filters,omitempty"`
}
type CollectionFilters struct {
OrderBy string `json:"orderBy,omitempty"`
JobType string `json:"jobType,omitempty"`
UserIDRankedScore string `json:"user_id_ranked_score,omitempty"`
ShowFilters bool `json:"showFilters,omitempty"`
}
func (c *Client) PutCollectionData(
ctx context.Context,
collectionID string,
data *CollectionData,
) (*Collection, error) {
if collectionID == "" {
return nil, ErrCollectionIDRequired
}
req := &Collection{
ID: collectionID,
Data: data,
}
resp := &Collection{}
err := c.Put(ctx, "app/collections/", nil, req, resp)
return resp, err
}
func (c *Client) PutCollectionFilters(
ctx context.Context,
collectionID string,
filters *CollectionFilters,
) (*Collection, error) {
if collectionID == "" {
return nil, ErrCollectionIDRequired
}
req := &Collection{
ID: collectionID,
Data: &CollectionData{
Filters: filters,
},
}
resp := &Collection{}
err := c.Put(ctx, "app/collections/", nil, req, resp)
return resp, err
}

60
collection_jobs.go Normal file
View File

@@ -0,0 +1,60 @@
package midjourney
import (
"context"
"fmt"
"net/http"
)
var ErrJobIDsRequired = fmt.Errorf("%w: job IDs required", Err)
type collectionJobsRequest struct {
CollectionID string `json:"collection_id,omitempty"`
JobIDs []string `json:"job_ids,omitempty"`
}
type CollectionJobsResult struct {
Failures []string `json:"failures,omitempty"`
Success bool `json:"success,omitempty"`
Successes []string `json:"successes,omitempty"`
}
func (c *Client) CollectionJobsAdd(
ctx context.Context,
collectionID string,
jobIDs []string,
) (*CollectionJobsResult, error) {
return c.collectionJobs(ctx, http.MethodPut, collectionID, jobIDs)
}
func (c *Client) CollectionJobsRemove(
ctx context.Context,
collectionID string,
jobIDs []string,
) (*CollectionJobsResult, error) {
return c.collectionJobs(ctx, http.MethodDelete, collectionID, jobIDs)
}
func (c *Client) collectionJobs(
ctx context.Context,
method string,
collectionID string,
jobIDs []string,
) (*CollectionJobsResult, error) {
if collectionID == "" {
return nil, ErrCollectionIDRequired
}
if len(jobIDs) == 0 {
return nil, ErrJobIDsRequired
}
var resp *CollectionJobsResult
err := c.Request(
ctx, method, "app/collections-jobs/", nil,
&collectionJobsRequest{CollectionID: collectionID, JobIDs: jobIDs},
resp,
)
return resp, err
}

114
collections.go Normal file
View File

@@ -0,0 +1,114 @@
package midjourney
import (
"context"
"fmt"
"net/url"
)
var (
ErrCollectionIDRequired = fmt.Errorf("%w: collection id required", Err)
ErrCollectionNotFound = fmt.Errorf("%w: collection", ErrNotFound)
)
type Collection struct {
CoverJobID string `json:"cover_job_id,omitempty"`
Created string `json:"created,omitempty"`
CreatorAvatarJobID string `json:"creator_avatar_job_id,omitempty"`
CreatorCoverJobID string `json:"creator_cover_job_id,omitempty"`
CreatorID string `json:"creator_id,omitempty"`
CreatorUsername string `json:"creator_username,omitempty"`
Data *CollectionData `json:"data,omitempty"`
Description string `json:"description,omitempty"`
Hidden bool `json:"hidden,omitempty"`
ID string `json:"id,omitempty"`
NumJobs int `json:"num_jobs,omitempty"`
Public bool `json:"public,omitempty"`
PublicEditable bool `json:"public_editable,omitempty"`
SearchTerms []string `json:"search_terms,omitempty"`
Title string `json:"title,omitempty"`
Workspaces []string `json:"workspaces,omitempty"`
}
type CollectionsQuery struct {
UserID string `url:"user_id,omitempty"`
CollectionID string `url:"collection_id,omitempty"`
}
func (cq *CollectionsQuery) URLValues() url.Values {
v := url.Values{}
if cq.UserID != "" {
v.Set("user_id", cq.UserID)
}
if cq.CollectionID != "" {
v.Set("collection_id", cq.CollectionID)
}
return v
}
func (c *Client) Collections(
ctx context.Context,
query *CollectionsQuery,
) ([]*Collection, error) {
var collections []*Collection
err := c.Get(ctx, "app/collections/", query.URLValues(), &collections)
return collections, err
}
func (c *Client) GetCollection(
ctx context.Context,
collectionID string,
) (*Collection, error) {
if collectionID == "" {
return nil, ErrCollectionIDRequired
}
q := &CollectionsQuery{CollectionID: collectionID}
var cols []*Collection
// Deletion of a collection is strangely done by setting the hidden flag to
// true. This is a bit confusing, but it's how the API works.
err := c.Get(ctx, "app/collections/", q.URLValues(), &cols)
if len(cols) == 0 {
return nil, fmt.Errorf("%w: id=%s", ErrCollectionNotFound, collectionID)
}
return cols[0], err
}
func (c *Client) PutCollection(
ctx context.Context,
collection *Collection,
) (*Collection, error) {
var col *Collection
err := c.Put(ctx, "app/collections/", nil, collection, col)
return col, err
}
func (c *Client) DeleteCollection(
ctx context.Context,
collectionID string,
) (*Collection, error) {
if collectionID == "" {
return nil, ErrCollectionIDRequired
}
var col *Collection
// Deletion of a collection is strangely done by setting the hidden flag to
// true. This is a bit confusing, but it's how the API works.
err := c.Put(
ctx, "app/collections/", nil,
&Collection{ID: collectionID, Hidden: true}, col,
)
return col, err
}

View File

@@ -33,6 +33,7 @@ type RecentJobsQuery struct {
JobStatus JobStatus
UserID string
UserIDLiked string
CollectionID string
FromDate time.Time
Page int
Prompt string
@@ -64,6 +65,9 @@ func (rjq *RecentJobsQuery) URLValues() url.Values {
if rjq.UserIDLiked != "" {
v.Set("userIdLiked", rjq.UserIDLiked)
}
if rjq.CollectionID != "" {
v.Set("collectionID", rjq.CollectionID)
}
if !rjq.FromDate.IsZero() {
v.Set("fromDate", rjq.FromDate.Format(FromDateFormat))
}
@@ -183,3 +187,21 @@ func (c *Client) Bookmarks(
Dedupe: true,
})
}
func (c *Client) CollectionFeed(
ctx context.Context,
collectionID string,
) (*RecentJobs, error) {
if collectionID == "" {
return nil, ErrCollectionIDRequired
}
return c.RecentJobs(ctx, &RecentJobsQuery{
Amount: 50,
JobType: JobTypeNull,
OrderBy: OrderNew,
JobStatus: JobStatusCompleted,
CollectionID: collectionID,
Dedupe: true,
})
}