refactor(commands): split commands package into multiple sub-packages

This commit is contained in:
2022-12-11 22:19:23 +00:00
parent 7fdd61b54c
commit c7c6553e53
8 changed files with 172 additions and 137 deletions

View File

@@ -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,
)

View File

@@ -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)
}
}

View File

@@ -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"`
}

View File

@@ -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"`
}

View File

@@ -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
}

View File

@@ -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("", " ")

View File

@@ -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
}

5
commands/shared/run.go Normal file
View File

@@ -0,0 +1,5 @@
package shared
import "github.com/spf13/cobra"
type RunEFunc func(cmd *cobra.Command, _ []string) error