From c7c6553e53d3c16da121a6d84dc55d2084521473 Mon Sep 17 00:00:00 2001 From: Jim Myhrberg Date: Sun, 11 Dec 2022 22:19:23 +0000 Subject: [PATCH] refactor(commands): split commands package into multiple sub-packages --- commands/{ => midjourney}/midjourney.go | 13 +- commands/midjourney/recent_jobs.go | 116 ++++++++++++++++++ .../words.go} | 28 +++-- commands/midjourney_recent_jobs.go | 96 --------------- commands/mje.go | 24 ++-- commands/{ => render}/render.go | 14 +-- commands/shared/flag_string.go | 13 ++ commands/shared/run.go | 5 + 8 files changed, 172 insertions(+), 137 deletions(-) rename commands/{ => midjourney}/midjourney.go (58%) create mode 100644 commands/midjourney/recent_jobs.go rename commands/{midjourney_words.go => midjourney/words.go} (75%) delete mode 100644 commands/midjourney_recent_jobs.go rename commands/{ => render}/render.go (66%) create mode 100644 commands/shared/flag_string.go create mode 100644 commands/shared/run.go diff --git a/commands/midjourney.go b/commands/midjourney/midjourney.go similarity index 58% rename from commands/midjourney.go rename to commands/midjourney/midjourney.go index b007e18..aac7624 100644 --- a/commands/midjourney.go +++ b/commands/midjourney/midjourney.go @@ -1,27 +1,32 @@ -package commands +package midjourney import ( "github.com/jimeh/go-midjourney" "github.com/spf13/cobra" ) -func NewMidjourney(mc *midjourney.Client) (*cobra.Command, error) { +func New(mc *midjourney.Client) (*cobra.Command, error) { cmd := &cobra.Command{ Use: "midjourney", Aliases: []string{"mj"}, Short: "Query the Midjourney API directly", } - recentJobsCmd, err := NewMidjourneyRecentJobs(mc) + collectionsCmd, err := NewCollections(mc) if err != nil { return nil, err } - wordsCmd, err := NewMidjourneyWords(mc) + recentJobsCmd, err := NewRecentJobs(mc) + if err != nil { + return nil, err + } + wordsCmd, err := NewWords(mc) if err != nil { return nil, err } cmd.AddCommand( + collectionsCmd, recentJobsCmd, wordsCmd, ) diff --git a/commands/midjourney/recent_jobs.go b/commands/midjourney/recent_jobs.go new file mode 100644 index 0000000..f87e6a0 --- /dev/null +++ b/commands/midjourney/recent_jobs.go @@ -0,0 +1,116 @@ +package midjourney + +import ( + "time" + + "github.com/jimeh/go-midjourney" + "github.com/jimeh/mje/commands/render" + "github.com/jimeh/mje/commands/shared" + "github.com/spf13/cobra" +) + +type Job struct { + ID string `json:"id,omitempty" yaml:"id,omitempty"` + Status string `json:"current_status,omitempty" yaml:"current_status,omitempty"` + Type string `json:"type,omitempty" yaml:"type,omitempty"` + EnqueueTime time.Time `json:"enqueue_time,omitempty" yaml:"enqueue_time,omitempty"` + Prompt string `json:"prompt,omitempty" yaml:"prompt,omitempty"` + ImagePaths []string `json:"image_paths,omitempty" yaml:"image_paths,omitempty"` + ThumbnailURLs *ThumbnailURLs `json:"thumbnail_urls,omitempty" yaml:"thumbnail_url,omitempty"` + IsPublished bool `json:"is_published,omitempty" yaml:"is_published,omitempty"` + UserID string `json:"user_id,omitempty" yaml:"user_id,omitempty"` + Username string `json:"username,omitempty" yaml:"username,omitempty"` + FullCommand string `json:"full_command,omitempty" yaml:"full_command,omitempty"` + ReferenceJobID string `json:"reference_job_id,omitempty" yaml:"reference_job_id,omitempty"` +} + +type ThumbnailURLs struct { + Small string `json:"small,omitempty" yaml:"small,omitempty"` + Medium string `json:"medium,omitempty" yaml:"medium,omitempty"` + Large string `json:"large,omitempty" yaml:"large,omitempty"` +} + +func NewRecentJobs(mc *midjourney.Client) (*cobra.Command, error) { + cmd := &cobra.Command{ + Use: "recent-jobs", + Aliases: []string{"jobs", "recent", "rj", "j", "r"}, + Short: "List recent jobs", + RunE: recentJobsRunE(mc), + } + + cmd.Flags().StringP("format", "f", "", "output format (yaml or json)") + cmd.Flags().IntP("amount", "a", 50, "amount of jobs to list") + cmd.Flags().StringP("type", "t", "", "type of jobs to list") + cmd.Flags().StringP("order", "o", "new", "either \"new\" or \"oldest\"") + cmd.Flags().StringP("user-id", "u", "", "user ID to list jobs for") + cmd.Flags().StringP( + "collection-id", "c", "", "collection ID to list jobs for", + ) + cmd.Flags().IntP("page", "p", 0, "page to fetch") + cmd.Flags().StringP("prompt", "s", "", "prompt text to search for") + cmd.Flags().Bool("dedupe", true, "dedupe results") + + return cmd, nil +} + +func recentJobsRunE(mc *midjourney.Client) shared.RunEFunc { + return func(cmd *cobra.Command, _ []string) error { + fs := cmd.Flags() + q := &midjourney.RecentJobsQuery{} + + if v, err := fs.GetInt("amount"); err == nil && v > 0 { + q.Amount = v + } + if v, err := fs.GetString("type"); err == nil && v != "" { + q.JobType = midjourney.JobType(v) + } + if v, err := fs.GetString("order"); err == nil && v != "" { + q.OrderBy = midjourney.Order(v) + } + if v, err := fs.GetString("user-id"); err == nil && v != "" { + q.UserID = v + } + if v, err := fs.GetString("collection-id"); err == nil && v != "" { + q.CollectionID = v + } + if v, err := fs.GetInt("page"); err == nil && v != 0 { + q.Page = v + } + if v, err := fs.GetString("prompt"); err == nil && v != "" { + q.Prompt = v + } + if v, err := fs.GetBool("dedupe"); err == nil { + q.Dedupe = v + } + + rj, err := mc.RecentJobs(cmd.Context(), q) + if err != nil { + return err + } + + r := []*Job{} + for _, j := range rj.Jobs { + r = append(r, &Job{ + ID: j.ID, + Status: string(j.CurrentStatus), + Type: string(j.Type), + EnqueueTime: j.EnqueueTime.Time, + Prompt: j.Prompt, + ImagePaths: j.ImagePaths, + ThumbnailURLs: &ThumbnailURLs{ + Small: j.ThumbnailURL(midjourney.ThumbnailSizeSmall), + Medium: j.ThumbnailURL(midjourney.ThumbnailSizeMedium), + Large: j.ThumbnailURL(midjourney.ThumbnailSizeLarge), + }, + IsPublished: j.IsPublished, + UserID: j.UserID, + Username: j.Username, + FullCommand: j.FullCommand, + ReferenceJobID: j.ReferenceJobID, + }) + } + format := shared.FlagString(cmd, "format") + + return render.Render(cmd.OutOrStdout(), format, r) + } +} diff --git a/commands/midjourney_words.go b/commands/midjourney/words.go similarity index 75% rename from commands/midjourney_words.go rename to commands/midjourney/words.go index 5509686..7a69b51 100644 --- a/commands/midjourney_words.go +++ b/commands/midjourney/words.go @@ -1,18 +1,25 @@ -package commands +package midjourney import ( "sort" "github.com/jimeh/go-midjourney" + "github.com/jimeh/mje/commands/render" + "github.com/jimeh/mje/commands/shared" "github.com/spf13/cobra" ) -func NewMidjourneyWords(mc *midjourney.Client) (*cobra.Command, error) { +type Word struct { + Word string `json:"word"` + ImageURL string `json:"image_url"` +} + +func NewWords(mc *midjourney.Client) (*cobra.Command, error) { cmd := &cobra.Command{ Use: "words", Aliases: []string{"w"}, Short: "Get dictionary words", - RunE: midjourneyWordsRunE(mc), + RunE: wordsRunE(mc), } cmd.Flags().StringP("format", "f", "", "output format (yaml or json)") @@ -24,7 +31,7 @@ func NewMidjourneyWords(mc *midjourney.Client) (*cobra.Command, error) { return cmd, nil } -func midjourneyWordsRunE(mc *midjourney.Client) runEFunc { +func wordsRunE(mc *midjourney.Client) shared.RunEFunc { return func(cmd *cobra.Command, _ []string) error { fs := cmd.Flags() q := &midjourney.WordsQuery{} @@ -47,24 +54,19 @@ func midjourneyWordsRunE(mc *midjourney.Client) runEFunc { return err } - r := []*MidjourneyWord{} + r := []*Word{} for _, w := range words { - r = append(r, &MidjourneyWord{ + r = append(r, &Word{ Word: w.Word, ImageURL: w.ImageURL(), }) } - format := flagString(cmd, "format") + format := shared.FlagString(cmd, "format") sort.SliceStable(r, func(i, j int) bool { return r[i].Word < r[j].Word }) - return render(cmd.OutOrStdout(), format, r) + return render.Render(cmd.OutOrStdout(), format, r) } } - -type MidjourneyWord struct { - Word string `json:"word"` - ImageURL string `json:"image_url"` -} diff --git a/commands/midjourney_recent_jobs.go b/commands/midjourney_recent_jobs.go deleted file mode 100644 index 6e51dc7..0000000 --- a/commands/midjourney_recent_jobs.go +++ /dev/null @@ -1,96 +0,0 @@ -package commands - -import ( - "time" - - "github.com/jimeh/go-midjourney" - "github.com/spf13/cobra" -) - -func NewMidjourneyRecentJobs(mc *midjourney.Client) (*cobra.Command, error) { - cmd := &cobra.Command{ - Use: "recent-jobs", - Aliases: []string{"jobs", "recent", "rj", "j", "r"}, - Short: "List recent jobs", - RunE: midjourneyRecentJobsRunE(mc), - } - - cmd.Flags().StringP("format", "f", "", "output format (yaml or json)") - cmd.Flags().IntP("amount", "a", 50, "amount of jobs to list") - cmd.Flags().StringP("type", "t", "", "type of jobs to list") - cmd.Flags().StringP("order", "o", "new", "either \"new\" or \"oldest\"") - cmd.Flags().StringP("user-id", "u", "", "user ID to list jobs for") - cmd.Flags().IntP("page", "p", 0, "page to fetch") - cmd.Flags().StringP("prompt", "s", "", "prompt text to search for") - cmd.Flags().Bool("dedupe", true, "dedupe results") - - return cmd, nil -} - -func midjourneyRecentJobsRunE(mc *midjourney.Client) runEFunc { - return func(cmd *cobra.Command, _ []string) error { - fs := cmd.Flags() - q := &midjourney.RecentJobsQuery{} - - if v, err := fs.GetInt("amount"); err == nil && v > 0 { - q.Amount = v - } - if v, err := fs.GetString("type"); err == nil && v != "" { - q.JobType = midjourney.JobType(v) - } - if v, err := fs.GetString("order"); err == nil && v != "" { - q.OrderBy = midjourney.Order(v) - } - if v, err := fs.GetString("user-id"); err == nil && v != "" { - q.UserID = v - } - if v, err := fs.GetInt("page"); err == nil && v != 0 { - q.Page = v - } - if v, err := fs.GetString("prompt"); err == nil && v != "" { - q.Prompt = v - } - if v, err := fs.GetBool("dedupe"); err == nil { - q.Dedupe = v - } - - rj, err := mc.RecentJobs(cmd.Context(), q) - if err != nil { - return err - } - - r := []*MidjourneyJob{} - for _, j := range rj.Jobs { - r = append(r, &MidjourneyJob{ - ID: j.ID, - Status: string(j.CurrentStatus), - Type: string(j.Type), - EnqueueTime: j.EnqueueTime.Time, - Prompt: j.Prompt, - ImagePaths: j.ImagePaths, - IsPublished: j.IsPublished, - UserID: j.UserID, - Username: j.Username, - FullCommand: j.FullCommand, - ReferenceJobID: j.ReferenceJobID, - }) - } - format := flagString(cmd, "format") - - return render(cmd.OutOrStdout(), format, r) - } -} - -type MidjourneyJob struct { - ID string `json:"id,omitempty" yaml:"id,omitempty"` - Status string `json:"current_status,omitempty" yaml:"current_status,omitempty"` - Type string `json:"type,omitempty" yaml:"type,omitempty"` - EnqueueTime time.Time `json:"enqueue_time,omitempty" yaml:"enqueue_time,omitempty"` - Prompt string `json:"prompt,omitempty" yaml:"prompt,omitempty"` - ImagePaths []string `json:"image_paths,omitempty" yaml:"image_paths,omitempty"` - IsPublished bool `json:"is_published,omitempty" yaml:"is_published,omitempty"` - UserID string `json:"user_id,omitempty" yaml:"user_id,omitempty"` - Username string `json:"username,omitempty" yaml:"username,omitempty"` - FullCommand string `json:"full_command,omitempty" yaml:"full_command,omitempty"` - ReferenceJobID string `json:"reference_job_id,omitempty" yaml:"reference_job_id,omitempty"` -} diff --git a/commands/mje.go b/commands/mje.go index 823bc65..ca71fb6 100644 --- a/commands/mje.go +++ b/commands/mje.go @@ -6,13 +6,13 @@ import ( "os" "github.com/jimeh/go-midjourney" + mjcmds "github.com/jimeh/mje/commands/midjourney" + "github.com/jimeh/mje/commands/shared" "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/spf13/cobra" ) -type runEFunc func(cmd *cobra.Command, _ []string) error - type Info struct { Version string Commit string @@ -52,7 +52,7 @@ func New(info Info) (*cobra.Command, error) { "MidJourney API URL", ) - midjourneyCmd, err := NewMidjourney(mc) + midjourneyCmd, err := mjcmds.New(mc) if err != nil { return nil, err } @@ -62,7 +62,7 @@ func New(info Info) (*cobra.Command, error) { return cmd, nil } -func persistentPreRunE(mc *midjourney.Client) runEFunc { +func persistentPreRunE(mc *midjourney.Client) shared.RunEFunc { return func(cmd *cobra.Command, _ []string) error { err := setupZerolog(cmd) if err != nil { @@ -89,7 +89,7 @@ func setupMidJourney(cmd *cobra.Command, mc *midjourney.Client) error { opts = append(opts, midjourney.WithAuthToken(v)) } - apiURL := flagString(cmd, "api-url") + apiURL := shared.FlagString(cmd, "api-url") if apiURL == "" { apiURL = os.Getenv("MIDJOURNEY_API_URL") } @@ -141,22 +141,12 @@ func setupZerolog(cmd *cobra.Command) error { case "plain": output := zerolog.ConsoleWriter{Out: out} output.FormatTimestamp = func(i interface{}) string { return "" } - log.Logger = zerolog.New(output).With().Logger() + log.Logger = zerolog.New(output).Level(level).With().Logger() case "json": - log.Logger = zerolog.New(out).With().Timestamp().Logger() + log.Logger = zerolog.New(out).Level(level) default: return fmt.Errorf("unknown log-format: %s", logFormat) } return nil } - -func flagString(cmd *cobra.Command, name string) string { - var r string - - if f := cmd.Flag(name); f != nil { - r = f.Value.String() - } - - return r -} diff --git a/commands/render.go b/commands/render/render.go similarity index 66% rename from commands/render.go rename to commands/render/render.go index 7c0d56e..4b3caf1 100644 --- a/commands/render.go +++ b/commands/render/render.go @@ -1,4 +1,4 @@ -package commands +package render import ( "encoding" @@ -8,13 +8,13 @@ import ( "gopkg.in/yaml.v3" ) -func render(w io.Writer, format string, v interface{}) error { +func Render(w io.Writer, format string, v any) error { if format == "yaml" || format == "yml" { - return renderYAML(w, v) + return YAML(w, v) } if format == "json" { - return renderJSON(w, v) + return JSON(w, v) } if wt, ok := v.(io.WriterTo); ok { @@ -34,17 +34,17 @@ func render(w io.Writer, format string, v interface{}) error { return err } - return renderJSON(w, v) + return JSON(w, v) } -func renderYAML(w io.Writer, v interface{}) error { +func YAML(w io.Writer, v interface{}) error { enc := yaml.NewEncoder(w) enc.SetIndent(2) return enc.Encode(v) } -func renderJSON(w io.Writer, v interface{}) error { +func JSON(w io.Writer, v interface{}) error { enc := json.NewEncoder(w) enc.SetIndent("", " ") diff --git a/commands/shared/flag_string.go b/commands/shared/flag_string.go new file mode 100644 index 0000000..e4b6744 --- /dev/null +++ b/commands/shared/flag_string.go @@ -0,0 +1,13 @@ +package shared + +import "github.com/spf13/cobra" + +func FlagString(cmd *cobra.Command, name string) string { + var r string + + if f := cmd.Flag(name); f != nil { + r = f.Value.String() + } + + return r +} diff --git a/commands/shared/run.go b/commands/shared/run.go new file mode 100644 index 0000000..2ccbf12 --- /dev/null +++ b/commands/shared/run.go @@ -0,0 +1,5 @@ +package shared + +import "github.com/spf13/cobra" + +type RunEFunc func(cmd *cobra.Command, _ []string) error