mjclient

package
v0.11.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 8, 2026 License: MIT Imports: 26 Imported by: 0

Documentation

Overview

Package mjclient is the Midjourney web client: it drives a Camoufox browser (via github.com/ehmo/gomoufox) to make authenticated, Cloudflare-passing calls to www.midjourney.com/api/*, and uses plain Go HTTP for the non-gated securetoken exchange and CDN downloads.

Index

Constants

This section is empty.

Variables

View Source
var ErrJobFailed = errors.New("job failed or was moderated")

ErrJobFailed is returned by Wait when a job reaches a failed/moderated state.

View Source
var ErrWaitTimeout = errors.New("timed out waiting for job")

ErrWaitTimeout is returned by Wait when the deadline elapses before terminal.

ExploreFeeds lists the valid feed values.

Functions

func DaemonAvailable

func DaemonAvailable(socket string) bool

DaemonAvailable reports whether a daemon is accepting connections at socket.

func DaemonSocketPath

func DaemonSocketPath() string

DaemonSocketPath returns the per-user daemon socket path, creating its dir.

func Redact

func Redact(s string) string

Redact replaces token-shaped substrings with <redacted>.

func ServeDaemon

func ServeDaemon(ctx context.Context, socket string, c *Client, idle time.Duration) error

ServeDaemon listens on socket and serves browser primitives from c's warm browser. Browser ops are serialized; submit-jobs are throttled across all clients by c's MinSubmitGap. If idle > 0, the daemon shuts down after that much inactivity. Returns when ctx is cancelled, a shutdown request arrives, idle expires, or the listener errors.

func StopDaemon

func StopDaemon(socket string) error

StopDaemon asks a running daemon to shut down.

func ValidFeed

func ValidFeed(f ExploreFeed) bool

ValidFeed reports whether f is a known explore feed.

Types

type APIError

type APIError struct {
	Status int
	Path   string
	Body   string // truncated, token-redacted preview
}

APIError is returned for non-2xx responses from www.midjourney.com/api/*.

func (*APIError) Code

func (e *APIError) Code() string

Code classifies the error for callers (CLI exit codes / MCP tool errors).

func (*APIError) Error

func (e *APIError) Error() string

func (*APIError) Retriable

func (e *APIError) Retriable() bool

Retriable reports whether retrying the request might succeed.

type AssetSel

type AssetSel string

AssetSel selects which CDN assets to download.

const (
	SelCells AssetSel = "cells" // individual grid cells 0_0.png..0_N.png
	SelGrid  AssetSel = "grid"  // composite grid_0.png only
	SelAll   AssetSel = "all"   // cells + grid
)

type AuthError

type AuthError struct{ Reason string }

AuthError indicates the credential chain could not establish a session.

func (*AuthError) Error

func (e *AuthError) Error() string

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is a connected Midjourney web client. Not safe for concurrent submits (callers serialize); read methods may interleave.

func DialDaemon

func DialDaemon(socket string, cfg Config) (*Client, error)

DialDaemon connects to a running daemon and returns a Client whose browser primitives execute on the daemon's warm browser.

func New

func New(ctx context.Context, cfg Config) (*Client, error)

New launches Camoufox, opens a page, and parks it on the midjourney.com origin so in-browser fetches send same-origin session cookies. It does not authenticate; call EnsureSession (or any API method, which auto-auths on 401).

func NewWithConn

func NewWithConn(conn pageConn, cfg Config) *Client

NewWithConn builds a Client over an existing transport (used by the daemon client to route browser primitives to a warm remote browser).

func Open

func Open(ctx context.Context, cfg Config) (*Client, error)

Open returns a Client routed through a running daemon when one is available (headless commands), otherwise a fresh local browser. Headful configs always get a local browser (the interactive login flow). This is the single entry point both the CLI and the MCP server use, so they share one warm browser + session when a daemon is running.

func (*Client) Account

func (c *Client) Account(ctx context.Context) (mjapi.Account, error)

Account returns the cached authUser, authenticating first if needed. When the transport is a daemon, it serves the daemon's warm account (no handshake). A locally-authed account older than accountTTL is refreshed proactively; if that refresh fails, the still-cached account is served (the next API call's 401 retry is the backstop).

func (*Client) Assets

func (c *Client) Assets(j mjapi.Job) []mjapi.AssetURL

Assets returns the derived CDN URLs for a completed job (see mjapi.Assets).

func (*Client) CDNHead

func (c *Client) CDNHead(ctx context.Context, j mjapi.Job) bool

CDNHead reports whether a job's first asset is available on the CDN yet (propagation check), fetched through the browser.

func (*Client) Close

func (c *Client) Close() error

Close shuts down the browser and sidecar.

func (*Client) CurrentRefreshToken

func (c *Client) CurrentRefreshToken() string

CurrentRefreshToken returns the refresh token most recently validated by EnsureSession (post-rotation). Empty until a session is established.

func (*Client) Describe

func (c *Client) Describe(ctx context.Context, imageURL string) ([]string, error)

Describe returns ~4 suggested prompts for an image. imageURL must be a public URL Midjourney can fetch (e.g. a cdn.midjourney.com image or any web image). /api/describe is synchronous — no job polling. Confirmed live 2026-06-05.

func (*Client) DescribeImage

func (c *Client) DescribeImage(ctx context.Context, pathOrURL string) ([]string, error)

DescribeImage describes a local file or a URL. URLs are described directly; local files are uploaded first.

func (*Client) Download

func (c *Client) Download(ctx context.Context, j mjapi.Job, destDir string, which AssetSel) ([]string, error)

Download fetches selected full-res PNG CDN assets (back-compat wrapper).

func (*Client) DownloadOpts

func (c *Client) DownloadOpts(ctx context.Context, j mjapi.Job, destDir string, which AssetSel, opts mjapi.AssetOpts) ([]string, error)

DownloadOpts fetches selected CDN assets for a completed job through the browser in the requested format/size and writes them to destDir. Returns the written file paths. Missing assets are retried briefly to absorb CDN propagation lag.

func (*Client) EnsureSession

func (c *Client) EnsureSession(ctx context.Context) error

EnsureSession (re)establishes the MJ session: fetch refresh token → securetoken → firebase-login → cache authUser. Persists a rotated refresh token to the CredStore when one is configured.

It is serialized by authMu so concurrent 401 retries don't run the token exchange twice (which can invalidate a rotated refresh token mid-flight). A caller that arrives just after another goroutine refreshed returns immediately rather than re-exchanging.

func (*Client) Explore

func (c *Client) Explore(ctx context.Context, feed ExploreFeed, page int) ([]mjapi.ExploreItem, error)

Explore browses the public explore gallery (page is 0-based, matching the web app's explore feed).

func (*Client) Folders

func (c *Client) Folders(ctx context.Context) ([]byte, error)

Folders returns the raw `/api/folders` JSON (collection structure varies; the shape is surfaced verbatim for now).

func (*Client) Get

func (c *Client) Get(ctx context.Context, path string) ([]byte, error)

Get performs an authenticated GET on a midjourney.com/api path (e.g. "/api/folders") and returns the raw body. Exposes the in-browser transport for read endpoints beyond the typed methods.

func (*Client) History

func (c *Client) History(ctx context.Context, pageSize int, cursor string) ([]mjapi.Job, string, error)

History returns the user's recent jobs (metadata only) and the next cursor.

func (*Client) ImageSize

func (c *Client) ImageSize(ctx context.Context, source string) (int, int, error)

ImageSize returns the width and height of a source image (local file or URL).

func (*Client) Imagine

func (c *Client) Imagine(ctx context.Context, req ImagineReq) (mjapi.Job, error)

Imagine submits a text→image generation (one job = one 4-image batch).

func (*Client) LikedStyles

func (c *Client) LikedStyles(ctx context.Context) ([]byte, error)

LikedStyles returns the raw `/api/explore-styles-likes` JSON (style objects; shape surfaced verbatim).

func (*Client) Likes

func (c *Client) Likes(ctx context.Context, page int) ([]mjapi.ExploreItem, error)

Likes returns the images the account has liked. page is 1-based, matching the web app (explore-likes rejects page=0 with 422).

func (*Client) Moodboards

func (c *Client) Moodboards(ctx context.Context) ([]mjapi.Moodboard, error)

Moodboards lists the account's personalization moodboards.

func (*Client) Outpaint

func (c *Client) Outpaint(ctx context.Context, source, prompt string, left, top, right, bottom int, mode mjapi.Mode) (mjapi.Job, error)

Outpaint extends the canvas around a source image by the given pixel margins and regenerates the new (transparent) area from prompt. Pan = margin on one side; zoom-out = margins on all sides. source is a local file or a URL.

func (*Client) PersonalizedProfiles

func (c *Client) PersonalizedProfiles(ctx context.Context) ([]byte, error)

PersonalizedProfiles returns the raw `/api/personalized-profiles` JSON.

func (*Client) PostJSON

func (c *Client) PostJSON(ctx context.Context, path string, body []byte) ([]byte, error)

PostJSON performs an authenticated POST with a JSON body on a midjourney.com /api path and returns the raw body.

func (*Client) ProfileFeed

func (c *Client) ProfileFeed(ctx context.Context, username string) ([]mjapi.ExploreItem, error)

ProfileFeed returns a user's published spotlight gallery by username.

func (*Client) Queue

func (c *Client) Queue(ctx context.Context) (mjapi.Queue, error)

Queue returns the account's running and waiting jobs.

func (*Client) ReadRefreshToken

func (c *Client) ReadRefreshToken(ctx context.Context) (string, error)

ReadRefreshToken returns the Firebase refresh token from the parked page's IndexedDB (populated after an interactive login). Empty string if not logged in.

func (*Client) Reroll

func (c *Client) Reroll(ctx context.Context, parent mjapi.JobID) (mjapi.Job, error)

Reroll re-runs a grid's prompt. [INFER] payload — confirm in Step 0.

func (*Client) Retexture

func (c *Client) Retexture(ctx context.Context, source, prompt, ar string, mode mjapi.Mode) (mjapi.Job, error)

Retexture re-renders an image's texture/style from a text instruction while keeping its structure, using the source as a depth reference (--dref). Confirmed live: t:"retexture" with the source uploaded and referenced as --dref in the prompt. source may be a local file or a URL.

func (*Client) SaveURL

func (c *Client) SaveURL(ctx context.Context, url, destPath string) error

SaveURL fetches an arbitrary CDN URL through the browser and writes it to destPath (creating parent dirs). Used for assets without a job (uploads).

func (*Client) Search

func (c *Client) Search(ctx context.Context, query string, page int) ([]mjapi.ExploreItem, error)

Search runs a semantic vector search over the public explore gallery. page is 1-based (matching the web app). Returns published community images.

func (*Client) Status

func (c *Client) Status(ctx context.Context, ids ...mjapi.JobID) ([]mjapi.Job, error)

Status fetches current_status (and metadata) for the given jobs.

func (*Client) Styles

func (c *Client) Styles(ctx context.Context, page int) ([]mjapi.ExploreItem, error)

Styles browses the public style-reference gallery (explore-srefs). Each result carries an sref code usable as `--sref <code>`. page is 0-based.

func (*Client) UploadBytes

func (c *Client) UploadBytes(ctx context.Context, data []byte, name string) (string, error)

UploadBytes uploads raw image bytes to Midjourney storage and returns a hosted URL (the short s.mj.run URL when available, else the cdn/u/ form).

func (*Client) UploadIfLocal

func (c *Client) UploadIfLocal(ctx context.Context, pathOrURL string) (string, error)

UploadIfLocal returns pathOrURL unchanged if it is a URL, otherwise uploads the local file and returns its hosted URL.

func (*Client) UploadImage

func (c *Client) UploadImage(ctx context.Context, localPath string) (string, error)

UploadImage uploads a local image to Midjourney's user storage and returns a public URL usable as an image_url / image prompt. Uses an in-browser multipart POST to /api/storage-upload-file.

func (*Client) Uploads

func (c *Client) Uploads(ctx context.Context) ([]mjapi.Upload, error)

Uploads lists the account's uploaded assets in personal storage.

func (*Client) Upscale

func (c *Client) Upscale(ctx context.Context, parent mjapi.JobID, index int, kind mjapi.UpscaleKind) (mjapi.Job, error)

Upscale upscales a grid cell.

func (*Client) Vary

func (c *Client) Vary(ctx context.Context, parent mjapi.JobID, index int, strong bool) (mjapi.Job, error)

Vary requests a variation of a grid cell.

func (*Client) VaryRegion

func (c *Client) VaryRegion(ctx context.Context, source, prompt string, x, y, rw, rh int, mode mjapi.Mode) (mjapi.Job, error)

VaryRegion erases a rectangular region of the source (making it transparent) and regenerates just that region from prompt, keeping the rest. source is a local file or a URL; the rect is in source pixels.

func (*Client) Video

func (c *Client) Video(ctx context.Context, req VideoReq) (mjapi.Job, error)

Video submits an image-to-video render from a grid cell.

func (*Client) Wait

func (c *Client) Wait(ctx context.Context, id mjapi.JobID, opts WaitOpts) (mjapi.Job, error)

Wait polls job-status until the job reaches a terminal state or the timeout elapses. Returns ErrJobFailed for failed/moderated, ErrWaitTimeout on deadline.

func (*Client) WatchConnect

func (c *Client) WatchConnect(ctx context.Context) bool

WatchConnect opens the realtime WebSocket and subscribes to the user BEFORE a job is submitted (the server only streams a job's frames to clients that were subscribed when it started). Returns true if the socket is open; false means callers should fall back to status polling. Requires a session-local websocketToken (local client only).

func (*Client) WatchJob

func (c *Client) WatchJob(ctx context.Context, id mjapi.JobID, wsOpen bool, timeout time.Duration, cb func(mjapi.Progress)) (mjapi.Job, error)

WatchJob streams progress for a job, calling cb on each percent/status change, until terminal or timeout. It drains WS frames for live percent and polls job-status as a backstop for reliable terminal detection. Returns the final job. If the WS isn't open (wsOpen=false) it polls only.

func (*Client) WatchProgress

func (c *Client) WatchProgress(ctx context.Context, id mjapi.JobID, timeout time.Duration, cb func(mjapi.Progress)) (mjapi.Job, error)

WatchProgress is a convenience wrapper: connect + watch a single job.

type Config

type Config struct {
	ProfileDir     string        // persistent Camoufox profile (session reuse); required for login persistence
	Headless       bool          // false = headful (login flow)
	RefreshToken   string        // optional explicit refresh token (overrides CredStore/IndexedDB)
	Proxy          string        // optional "http://host:port"
	ConnectTimeout time.Duration // browser connect timeout (default 60s)
	MinSubmitGap   time.Duration // throttle between submit-jobs (default 12s)
	Creds          CredStore     // optional credential store (hasp)
}

Config configures a Client.

type CredStore

type CredStore interface {
	Get(ctx context.Context) (string, error)
	Set(ctx context.Context, refreshToken string) error
}

CredStore persists the durable Firebase refresh token (e.g. hasp-backed).

type ExploreFeed

type ExploreFeed string

ExploreFeed selects the explore browse feed. Values confirmed live from the web app's feed selector.

const (
	FeedTop      ExploreFeed = "top"       // top all-time
	FeedTopWeek  ExploreFeed = "top_week"  // top this week
	FeedTopMonth ExploreFeed = "top_month" // top this month
	FeedHot      ExploreFeed = "hot"       // trending
	FeedRandom   ExploreFeed = "random"
	FeedVideos   ExploreFeed = "videos" // community videos
)

type FetchReq

type FetchReq struct {
	URL      string            `json:"url"`
	Method   string            `json:"method"`
	Headers  map[string]string `json:"headers"`
	Body     []byte            `json:"body"`
	MaxBytes int               `json:"max_bytes"`
}

FetchReq is an in-browser fetch request (to www.midjourney.com/api/* or CDN).

type FetchRes

type FetchRes struct {
	StatusCode int    `json:"status_code"`
	Body       []byte `json:"body"`
	Truncated  bool   `json:"truncated"`
}

FetchRes is the result of an in-browser fetch.

type ImagineReq

type ImagineReq struct {
	Prompt  string
	Params  mjapi.Params
	Mode    mjapi.Mode // default fast
	Private bool       // stealth (requires can_private)
}

ImagineReq is an imagine request.

type VideoReq

type VideoReq struct {
	Parent         mjapi.JobID
	Index          int    // grid image (1..4)
	Motion         string // "high" | "low" (default low)
	Mode           mjapi.Mode
	Private        bool
	NewPromptExtra string // optional extra prompt text; defaults to parent prompt server-side
}

VideoReq is an image-to-video request.

type WaitOpts

type WaitOpts struct {
	Timeout  time.Duration     // default 5m
	OnUpdate func(j mjapi.Job) // optional progress callback per poll
}

WaitOpts configures Wait.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL