@thenavidm/midjourney-mcp-cli 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -46
- package/SKILL.md +100 -35
- package/dist/api/download.js +2 -1
- package/dist/api/download.js.map +1 -1
- package/dist/api/jobs.d.ts +64 -0
- package/dist/api/jobs.js +124 -0
- package/dist/api/jobs.js.map +1 -1
- package/dist/api/moodboards.d.ts +13 -0
- package/dist/api/moodboards.js +15 -0
- package/dist/api/moodboards.js.map +1 -1
- package/dist/config.js +1 -1
- package/dist/format/jobs.d.ts +10 -0
- package/dist/format/jobs.js +27 -5
- package/dist/format/jobs.js.map +1 -1
- package/dist/index.js +14 -2
- package/dist/index.js.map +1 -1
- package/dist/tools/create.d.ts +41 -2
- package/dist/tools/create.js +159 -20
- package/dist/tools/create.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,35 +1,23 @@
|
|
|
1
|
-
<
|
|
2
|
-
<img src="https://cdn.navid.media/connectors/midjourney-icon.png" alt="Midjourney" width="88">
|
|
3
|
-
</div>
|
|
1
|
+
<img src="https://cdn.navid.media/connectors/midjourney-icon-solid.png" alt="Midjourney" width="88">
|
|
4
2
|
|
|
5
3
|
# Midjourney MCP + CLI
|
|
6
4
|
|
|
5
|
+
[](https://www.npmjs.com/package/@thenavidm/midjourney-mcp-cli)
|
|
7
6
|
[](./LICENSE)
|
|
8
7
|
[](https://youtube.com/@thenavidm?sub_confirmation=1)
|
|
9
8
|
[](https://x.com/thenavidm)
|
|
10
9
|
|
|
11
|
-
Midjourney MCP server and CLI for Claude Code and AI agents.
|
|
10
|
+
Midjourney MCP server and CLI for Claude Code and AI agents. 32 tools for generating images, following jobs to completion, downloading the real files, and building moodboards that make a style reusable.
|
|
12
11
|
|
|
13
12
|
Midjourney publishes no API, so this drives a real Chrome that is signed in as you.
|
|
14
13
|
|
|
15
14
|
There is no key to paste and no cookie to export. You sign in once, in a window, and the session lives in a browser profile rather than in a config file.
|
|
16
15
|
|
|
17
|
-
|
|
16
|
+
32 tools, on both surfaces. It waits for jobs to finish and hands back the actual files, not a screenshot of them.
|
|
18
17
|
|
|
19
18
|
Built and maintained by [Navid Moazzez](https://navid.me).
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
You: make a moodboard for cold Nordic product shots, fill it, then shoot a jar of face cream in that style
|
|
23
|
-
|
|
24
|
-
Claude: Built the board and used it.
|
|
25
|
-
|
|
26
|
-
moodboard Nordic Skincare | Still Life 4 images
|
|
27
|
-
job f44b0a9d-e184-4e18-811f-a1ef9482d286
|
|
28
|
-
prompt a ceramic jar of face cream, lid beside it
|
|
29
|
-
style from the moodboard, not the prompt
|
|
30
|
-
|
|
31
|
-
~/Downloads/midjourney/f44b0a9d-0.png 1.8 MB 960x1200
|
|
32
|
-
```
|
|
20
|
+
<img src="https://cdn.navid.media/repos/midjourney-mcp-cli.gif?v=2" alt="Claude Code using the Midjourney MCP server" width="520">
|
|
33
21
|
|
|
34
22
|
## Two ways to use it
|
|
35
23
|
|
|
@@ -73,12 +61,11 @@ Every other client is in [section 3](#3-install).
|
|
|
73
61
|
|
|
74
62
|
### Which one
|
|
75
63
|
|
|
76
|
-
|
|
|
64
|
+
| Where you are | What you can reach |
|
|
77
65
|
|---|---|
|
|
78
|
-
|
|
|
79
|
-
|
|
|
80
|
-
|
|
|
81
|
-
| A one-off question in a terminal | CLI |
|
|
66
|
+
| An agent that can run shell commands, like Claude Code or Cursor | Both. The CLI is the cheaper one: it costs nothing until you type it |
|
|
67
|
+
| claude.ai or a phone | Neither. Your logged-in browser is on this machine, and a cloud connector cannot reach it |
|
|
68
|
+
| A terminal, a script, cron or CI | The CLI only. There is no MCP client in a shell |
|
|
82
69
|
|
|
83
70
|
They are the same program reading the same tool definitions, so anything one
|
|
84
71
|
can do, the other can.
|
|
@@ -131,8 +118,8 @@ All 27 with their arguments are in [section 6](#6-tools).
|
|
|
131
118
|
| 11 | [Your data](#11-your-data) | What is stored and where |
|
|
132
119
|
| 12 | [Risks](#12-risks) | Read this before you install |
|
|
133
120
|
| 13 | [Troubleshooting](#13-troubleshooting) | When something breaks |
|
|
134
|
-
| | [Environment variables](#environment-variables) | Every knob, and its default |
|
|
135
|
-
|
|
|
121
|
+
| 14 | [Environment variables](#14-environment-variables) | Every knob, and its default |
|
|
122
|
+
| 15 | [FAQ](#15-faq) | Including what an MCP server is |
|
|
136
123
|
|
|
137
124
|
## 1. What you can ask it
|
|
138
125
|
|
|
@@ -141,6 +128,7 @@ All 27 with their arguments are in [section 6](#6-tools).
|
|
|
141
128
|
- Make a moodboard for cold Nordic product shots, fill it, then shoot a jar of face cream in that style
|
|
142
129
|
- Generate four logo concepts at low stylize so they stay literal, and save them
|
|
143
130
|
- Vary the second one, strong, and save the results
|
|
131
|
+
- Upscale that one and turn it into a video
|
|
144
132
|
- Take that last image's seed and try it again with chaos 40
|
|
145
133
|
- What is in my Midjourney queue right now?
|
|
146
134
|
- Download everything I generated today into ./renders
|
|
@@ -180,8 +168,6 @@ Node 22 or newer, and Google Chrome. Nothing else.
|
|
|
180
168
|
|
|
181
169
|
npx -y @thenavidm/midjourney-mcp-cli --version
|
|
182
170
|
|
|
183
|
-
> [!NOTE]
|
|
184
|
-
> Not published to npm yet. Until it is, clone the repo and run `npm install && npm run build`, then use `node dist/index.js` wherever this page says `npx -y @thenavidm/midjourney-mcp-cli@latest`.
|
|
185
171
|
|
|
186
172
|
Node 22 is the floor because the browser connection uses the global `WebSocket`
|
|
187
173
|
that landed in that release. That is also why it has no dependency doing it.
|
|
@@ -301,7 +287,7 @@ authorises a charge.
|
|
|
301
287
|
|
|
302
288
|
An MCP server is expensive and a CLI is free.
|
|
303
289
|
|
|
304
|
-
The `tools/list` payload for these
|
|
290
|
+
The `tools/list` payload for these 32 tools is about **11,062 tokens**, plus the
|
|
305
291
|
server instructions. That is charged on every turn of every conversation, used
|
|
306
292
|
or not, because the descriptions are long and carry the parameter grammar.
|
|
307
293
|
|
|
@@ -310,11 +296,10 @@ the model pays only when it runs something.
|
|
|
310
296
|
|
|
311
297
|
So the two are not competing:
|
|
312
298
|
|
|
313
|
-
| Where
|
|
299
|
+
| Where you are | What you can reach |
|
|
314
300
|
|---|---|
|
|
315
|
-
|
|
|
316
|
-
|
|
|
317
|
-
| A one-off question in a terminal | CLI |
|
|
301
|
+
| An agent that can run shell commands | Both. The CLI costs nothing until you type it |
|
|
302
|
+
| A terminal, a script, cron or CI | The CLI only |
|
|
318
303
|
|
|
319
304
|
## 6. Tools
|
|
320
305
|
|
|
@@ -326,6 +311,11 @@ So the two are not competing:
|
|
|
326
311
|
| `submit_imagine` | Submit and return the job id without waiting. Spends |
|
|
327
312
|
| `rerun_job` | Run an existing job again, optionally with new wording or at HD. Spends |
|
|
328
313
|
| `vary_image` | Four variations of one image from a grid, subtle or strong. Spends |
|
|
314
|
+
| `upscale_image` | Upscale one image to full resolution, subtle or creative. Spends |
|
|
315
|
+
| `animate_image` | Turn one image into a video. Spends |
|
|
316
|
+
| `pan_image` | Extend the frame left, right, up or down. Spends |
|
|
317
|
+
| `zoom_out` | Pull the camera back and fill the new space. Spends |
|
|
318
|
+
| `remix_image` | Re-render an image against a new prompt, keeping its composition. Spends |
|
|
329
319
|
| `submit_raw_job` | Send a job type this server does not model yet. Spends |
|
|
330
320
|
|
|
331
321
|
### Following work
|
|
@@ -429,29 +419,42 @@ At the terminal, Midjourney's own spellings work as aliases: `--ar`, `--sref`,
|
|
|
429
419
|
|
|
430
420
|
## 9. Moodboards
|
|
431
421
|
|
|
432
|
-
A moodboard is a
|
|
433
|
-
|
|
422
|
+
A moodboard is a set of images the account has curated. Applying one is the same
|
|
423
|
+
mechanism the web app's Personalize panel uses: the board becomes a
|
|
424
|
+
personalization code on the prompt, resolved for you from its name.
|
|
425
|
+
|
|
426
|
+
```bash
|
|
427
|
+
midjourney-cli imagine "a ceramic jar of face cream" --moodboard "Nordic Skincare" --confirm
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
That is worth stating because there is a plausible wrong way to do the same
|
|
431
|
+
thing: sampling the board's images into `--sref` URLs. It only registers at a
|
|
432
|
+
high `--sw`, and that weight is what makes output look over-processed. The
|
|
433
|
+
personalization code needs no weight and does not compete with your wording.
|
|
434
434
|
|
|
435
435
|
The loop:
|
|
436
436
|
|
|
437
437
|
```bash
|
|
438
|
-
midjourney-cli create-moodboard "Nordic Skincare
|
|
438
|
+
midjourney-cli create-moodboard "Nordic Skincare"
|
|
439
439
|
midjourney-cli imagine "<a long, specific style description>" --confirm
|
|
440
440
|
midjourney-cli add-to-moodboard "Nordic Skincare" --job-id <job>
|
|
441
|
-
midjourney-cli imagine "a ceramic jar of face cream
|
|
442
|
-
--moodboard "Nordic Skincare" --sw 400 --confirm
|
|
441
|
+
midjourney-cli imagine "a ceramic jar of face cream" --moodboard "Nordic Skincare" --confirm
|
|
443
442
|
```
|
|
444
443
|
|
|
445
|
-
After the third line the style is a name, and a nine-word prompt reproduces it.
|
|
446
|
-
|
|
447
444
|
Partial names work: `"High Fashion"` finds `"High Fashion | Woman"`. An ambiguous
|
|
448
445
|
name errors with the candidates rather than guessing, because picking the wrong
|
|
449
|
-
board costs a generation to discover.
|
|
450
|
-
|
|
451
|
-
|
|
446
|
+
board costs a generation to discover.
|
|
447
|
+
|
|
448
|
+
`--p` accepts several codes, so a moodboard and a personalization profile apply
|
|
449
|
+
together. `profile` is the other kind of personalization: it biases toward
|
|
450
|
+
images the account has rated, rather than toward a set of pictures.
|
|
451
|
+
|
|
452
|
+
### Leave the sliders alone
|
|
452
453
|
|
|
453
|
-
|
|
454
|
-
|
|
454
|
+
Midjourney's own defaults for stylize, weirdness and variety sit near the
|
|
455
|
+
minimum. Raising `stylize` trades fidelity for a prettier, more generic image.
|
|
456
|
+
Set them when you want that; otherwise a strong result comes from the prompt and
|
|
457
|
+
the reference.
|
|
455
458
|
|
|
456
459
|
## 10. How it works
|
|
457
460
|
|
|
@@ -524,7 +527,7 @@ Start with `doctor`. It orders the checks so the first failure is the one to fix
|
|
|
524
527
|
| Every command times out at once | A native dialog was left open in the window. Dialogs are auto-dismissed now; if it persists, close the tab |
|
|
525
528
|
| Downloads are empty or fail | The asset URL expired. Re-read the job with `get_job` for fresh URLs |
|
|
526
529
|
|
|
527
|
-
## Environment variables
|
|
530
|
+
## 14. Environment variables
|
|
528
531
|
|
|
529
532
|
Every one of these is optional. The defaults are what you want unless you are doing something unusual.
|
|
530
533
|
|
|
@@ -553,7 +556,7 @@ Every one of these is optional. The defaults are what you want unless you are do
|
|
|
553
556
|
| `MIDJOURNEY_HTTP_HOST` | `127.0.0.1` | Interface for `--http` |
|
|
554
557
|
| `MIDJOURNEY_HTTP_TOKEN` | unset | Bearer token. Required to listen off loopback |
|
|
555
558
|
|
|
556
|
-
##
|
|
559
|
+
## 15. FAQ
|
|
557
560
|
|
|
558
561
|
<details>
|
|
559
562
|
<summary><b>What is an MCP server?</b></summary>
|
|
@@ -650,7 +653,7 @@ Navid Moazzez is a leading AI business strategist, and the host of the AI Creato
|
|
|
650
653
|
**Links**
|
|
651
654
|
|
|
652
655
|
- Personal website: [navid.me](https://navid.me)
|
|
653
|
-
-
|
|
656
|
+
- Link in bio: [navid.bio](https://navid.bio)
|
|
654
657
|
- Navid Media: [navid.media](https://navid.media)
|
|
655
658
|
- YouTube: [@thenavidm](https://youtube.com/@thenavidm?sub_confirmation=1) and [@thenavidai](https://youtube.com/@thenavidai?sub_confirmation=1)
|
|
656
659
|
- X: [@thenavidm](https://x.com/thenavidm)
|
package/SKILL.md
CHANGED
|
@@ -68,10 +68,10 @@ The ones worth knowing:
|
|
|
68
68
|
| Argument | What it does |
|
|
69
69
|
|---|---|
|
|
70
70
|
| `aspect` | `"16:9"`, `"3:2"`, `"1:1"` |
|
|
71
|
-
| `stylize` | 0-1000.
|
|
72
|
-
| `chaos` | 0-100.
|
|
71
|
+
| `stylize` | 0-1000. Leave unset: the default is low and raising it costs fidelity |
|
|
72
|
+
| `chaos` | 0-100. Leave unset unless exploring |
|
|
73
73
|
| `seed` | Reuse with an identical prompt to iterate on one image, not roll a new one |
|
|
74
|
-
| `style_refs` |
|
|
74
|
+
| `style_refs` | One specific reference. For a curated look use `moodboard` instead |
|
|
75
75
|
| `omni_refs` | Carry a character or object across images. The v7 replacement for `--cref` |
|
|
76
76
|
| `image_prompts` | Direct image URLs, used as visual input |
|
|
77
77
|
| `negative` | Things to keep out, e.g. `"text, watermark"` |
|
|
@@ -82,52 +82,117 @@ The ones worth knowing:
|
|
|
82
82
|
At the terminal, Midjourney's own spellings work as aliases: `--ar`, `--sref`,
|
|
83
83
|
`--oref`, `--iw`, `--sw`, `--ow`, `--q`, `--no`, `--v`.
|
|
84
84
|
|
|
85
|
-
##
|
|
85
|
+
## Use the newest model unless told otherwise
|
|
86
86
|
|
|
87
|
-
The
|
|
88
|
-
|
|
87
|
+
The default is the current model, v8.2. Only pin an older one when the user asks
|
|
88
|
+
for it, or when they are iterating on an image made with it and want the match.
|
|
89
89
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
## Moodboards are the strongest styling tool, and they are not srefs
|
|
91
|
+
|
|
92
|
+
A moodboard is a collection of images the account has curated. Applying one is
|
|
93
|
+
the same mechanism as selecting it in the web app's Personalize panel: the board
|
|
94
|
+
becomes a **personalization code** on the prompt.
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
midjourney-cli imagine "a ceramic jar of face cream" --moodboard "Nordic Skincare" --confirm
|
|
93
98
|
```
|
|
94
99
|
|
|
95
|
-
|
|
96
|
-
|
|
100
|
+
The code is the board's id with an `m` in front, and the tool resolves it for
|
|
101
|
+
you. This matters because there is an obvious wrong way to do the same thing:
|
|
102
|
+
sampling the board's images into `--sref` URLs. That approximation only shows up
|
|
103
|
+
at a high `--sw`, and that weight is what makes output look processed. Use the
|
|
104
|
+
moodboard.
|
|
97
105
|
|
|
98
|
-
`
|
|
99
|
-
|
|
100
|
-
references a generation would use.
|
|
106
|
+
`--p` accepts more than one code, so a moodboard and a personalization profile
|
|
107
|
+
can apply together.
|
|
101
108
|
|
|
102
|
-
|
|
103
|
-
rated, rather than toward a set of pictures. `list_personalized_profiles`
|
|
104
|
-
reports how many ratings each is built on, and one with a low count barely
|
|
105
|
-
moves the result.
|
|
109
|
+
Three styling tools, three jobs:
|
|
106
110
|
|
|
107
|
-
|
|
111
|
+
| Want | Use |
|
|
112
|
+
|---|---|
|
|
113
|
+
| A look the account has curated | `moodboard` |
|
|
114
|
+
| One specific reference image or code | `style_refs` |
|
|
115
|
+
| The same character or object across images | `omni_refs` |
|
|
116
|
+
| The account's learned taste | `profile` |
|
|
108
117
|
|
|
109
|
-
|
|
110
|
-
for, and it is worth driving deliberately.
|
|
118
|
+
## Leave stylize, chaos and weird alone
|
|
111
119
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
add_to_moodboard(moodboard: "Nordic Skincare", job_id: "<the job>", confirm: true)
|
|
116
|
-
```
|
|
120
|
+
Midjourney's own defaults sit low, and the sliders in its settings panel start
|
|
121
|
+
near the minimum. Raising `stylize` trades fidelity for a prettier, more
|
|
122
|
+
generic image; `chaos` and `weird` are for exploring, not for quality.
|
|
117
123
|
|
|
118
|
-
|
|
124
|
+
Reach for them only when the user asks for more stylisation or more variety. A
|
|
125
|
+
strong result comes from the prompt and the reference, not from the knobs.
|
|
119
126
|
|
|
127
|
+
## Write prompts that leave nothing to chance
|
|
128
|
+
|
|
129
|
+
Vague adjectives produce generic images. Specificity is what earns the output.
|
|
130
|
+
Compare:
|
|
131
|
+
|
|
132
|
+
> a beautiful woman in a knit set, studio, high quality, 8k
|
|
133
|
+
|
|
134
|
+
against
|
|
135
|
+
|
|
136
|
+
> a woman in three-quarter turn against a seamless clay cyclorama, rib-knit set
|
|
137
|
+
> in oat, one hand at the hip, chin level, lit by a single large softbox high
|
|
138
|
+
> and slightly left with a white bounce filling the shadow side so the falloff
|
|
139
|
+
> is gentle, shot on medium format at f5.6, skin unretouched with visible pores,
|
|
140
|
+
> nothing else in frame
|
|
141
|
+
|
|
142
|
+
The second names the pose, the light source and its position, the fill, how the
|
|
143
|
+
falloff should behave, the camera and aperture, what the skin keeps, and what
|
|
144
|
+
must not appear. Every one of those is a decision the model would otherwise make
|
|
145
|
+
for you.
|
|
146
|
+
|
|
147
|
+
Things worth stating explicitly, because the model will invent them otherwise:
|
|
148
|
+
|
|
149
|
+
- **Where the light comes from**, and what fills the shadow
|
|
150
|
+
- **What the camera is**, and the aperture, which sets how much falls off
|
|
151
|
+
- **What the subject is doing** with hands, shoulders, gaze
|
|
152
|
+
- **What must not be in frame**, via the prompt or `negative`
|
|
153
|
+
- **The palette**, named as colours rather than a mood
|
|
154
|
+
- **Skin, fabric and surface texture**, or you get plastic
|
|
155
|
+
|
|
156
|
+
`raw` is worth setting for anything photographic: it applies less of
|
|
157
|
+
Midjourney's automatic prettification.
|
|
158
|
+
|
|
159
|
+
## The pipeline is where the good work happens
|
|
160
|
+
|
|
161
|
+
One generation is a draft. The tools exist to take it somewhere:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
# 1. Explore cheaply. Draft mode is fast and costs less.
|
|
165
|
+
midjourney-cli imagine "<a long, specific prompt>" --draft --confirm
|
|
166
|
+
|
|
167
|
+
# 2. Once the composition is right, run it properly and keep the seed.
|
|
168
|
+
midjourney-cli imagine "<the same prompt>" --seed 501058481 --raw --confirm
|
|
169
|
+
|
|
170
|
+
# 3. Push the one that is closest.
|
|
171
|
+
midjourney-cli vary-image <job> --index 2 --confirm # subtle, or --strong
|
|
172
|
+
midjourney-cli remix-image <job> --index 2 --prompt "<reworded>" --confirm
|
|
173
|
+
|
|
174
|
+
# 4. Give it room, or take the frame wider.
|
|
175
|
+
midjourney-cli zoom-out <job> --index 2 --zoom-factor 150 --confirm
|
|
176
|
+
midjourney-cli pan-image <job> --index 2 --direction left --confirm
|
|
177
|
+
|
|
178
|
+
# 5. Finish it.
|
|
179
|
+
midjourney-cli upscale-image <job> --index 2 --confirm # subtle, or creative
|
|
180
|
+
midjourney-cli animate-image <job> --index 2 --motion "slow push in" --confirm
|
|
181
|
+
midjourney-cli download-job <job> --out-dir ./renders
|
|
120
182
|
```
|
|
121
|
-
imagine(prompt: "a ceramic jar of face cream, lid beside it",
|
|
122
|
-
moodboard: "Nordic Skincare", moodboard_refs: 4, confirm: true)
|
|
123
|
-
```
|
|
124
183
|
|
|
125
|
-
|
|
126
|
-
|
|
184
|
+
`seed` is how you iterate rather than reroll: the same prompt and seed gives a
|
|
185
|
+
near-identical image, so a small wording change shows its own effect instead of
|
|
186
|
+
a new roll of the dice.
|
|
187
|
+
|
|
188
|
+
`zoom_out` before adding a headline or a logo: it gives the composition room
|
|
189
|
+
without regenerating it.
|
|
190
|
+
|
|
191
|
+
`upscale` subtle keeps what is there; creative reworks detail as it enlarges, so
|
|
192
|
+
it is the wrong choice when the image is already right.
|
|
127
193
|
|
|
128
|
-
`
|
|
129
|
-
|
|
130
|
-
undone, so it asks for confirmation.
|
|
194
|
+
`animate_image` takes a `motion` note, not a scene: it is appended to the
|
|
195
|
+
image's own prompt, because Midjourney reads that field as what is in the frame.
|
|
131
196
|
|
|
132
197
|
## Working with results
|
|
133
198
|
|
package/dist/api/download.js
CHANGED
|
@@ -37,7 +37,8 @@ export function fileNameFor(url, jobId, index) {
|
|
|
37
37
|
// job in a folder, so the job id goes in front. The stem itself is dropped
|
|
38
38
|
// when it is just the grid position again: `<job>-0-0_0.png` says nothing
|
|
39
39
|
// that `<job>-0.png` does not.
|
|
40
|
-
|
|
40
|
+
// `0_2` for a grid image, `2` for a video segment: both repeat the index.
|
|
41
|
+
const redundant = /^\d+(_\d+)?$/.test(stem);
|
|
41
42
|
const safeStem = redundant ? "" : stem.replace(/[^a-zA-Z0-9._-]/g, "-").slice(0, 60);
|
|
42
43
|
return `${jobId}-${index}${safeStem ? `-${safeStem}` : ""}${extension}`;
|
|
43
44
|
}
|
package/dist/api/download.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"download.js","sourceRoot":"","sources":["../../src/api/download.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAG7D,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AASlD,qFAAqF;AACrF,MAAM,UAAU,WAAW,CAAC,GAAW,EAAE,KAAa,EAAE,KAAa;IACnE,IAAI,SAAS,GAAG,EAAE,CAAC;IACnB,IAAI,CAAC;QACH,SAAS,GAAG,QAAQ,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,SAAS,GAAG,EAAE,CAAC;IACjB,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,IAAI,YAAY,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;IACvE,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAE/F,4EAA4E;IAC5E,2EAA2E;IAC3E,0EAA0E;IAC1E,+BAA+B;IAC/B,MAAM,SAAS,GAAG,
|
|
1
|
+
{"version":3,"file":"download.js","sourceRoot":"","sources":["../../src/api/download.ts"],"names":[],"mappings":"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"}
|
package/dist/api/jobs.d.ts
CHANGED
|
@@ -91,6 +91,70 @@ export declare function submitRaw(client: MidjourneyClient, jobType: string, ext
|
|
|
91
91
|
jobIds: string[];
|
|
92
92
|
raw: unknown;
|
|
93
93
|
}>;
|
|
94
|
+
/**
|
|
95
|
+
* Which upscaler a job can use, derived from the model that made it.
|
|
96
|
+
*
|
|
97
|
+
* The menu says "Subtle" and "Creative", but the wire wants a version-specific
|
|
98
|
+
* name: `v8r1_2x_subtle` for a v8.1 image, `v7_2x_creative` for a v7 one. Send
|
|
99
|
+
* the label and the request is refused. None of this is guessable, and it is
|
|
100
|
+
* why the first four attempts here were 400s.
|
|
101
|
+
*/
|
|
102
|
+
export declare function upscalerFor(version: string | undefined, style: "subtle" | "creative"): string;
|
|
103
|
+
/** The model version a job was made with, read off the job itself. */
|
|
104
|
+
export declare function versionOfJob(job: {
|
|
105
|
+
jobType?: string;
|
|
106
|
+
prompt?: string;
|
|
107
|
+
} | undefined): string | undefined;
|
|
108
|
+
/** Upscale one image from a grid. `subtle` keeps it; `creative` reworks detail. */
|
|
109
|
+
export declare function submitUpscale(client: MidjourneyClient, jobId: string, index: number, style: "subtle" | "creative", options?: SubmitOptions & {
|
|
110
|
+
version?: string;
|
|
111
|
+
}): Promise<{
|
|
112
|
+
jobIds: string[];
|
|
113
|
+
raw: unknown;
|
|
114
|
+
}>;
|
|
115
|
+
/**
|
|
116
|
+
* Animate one image into a video.
|
|
117
|
+
*
|
|
118
|
+
* Two things here are not guessable and both cost a rejected request to learn.
|
|
119
|
+
* The source is nested under `parentJob` as `image_num`, not the flat `index`
|
|
120
|
+
* every other job type uses. And `newPrompt` carries the image's own prompt,
|
|
121
|
+
* not a description of the motion: passing "slow push in" on its own is
|
|
122
|
+
* refused, because the field is the scene, not the movement.
|
|
123
|
+
*
|
|
124
|
+
* So a motion note is appended to the original prompt rather than replacing
|
|
125
|
+
* it, which is what the web app does when you type into its box.
|
|
126
|
+
*/
|
|
127
|
+
export declare function submitVideo(client: MidjourneyClient, jobId: string, index: number, opts?: SubmitOptions & {
|
|
128
|
+
motion?: string;
|
|
129
|
+
resolution?: "480" | "720";
|
|
130
|
+
mode?: "auto" | "manual";
|
|
131
|
+
}): Promise<{
|
|
132
|
+
jobIds: string[];
|
|
133
|
+
raw: unknown;
|
|
134
|
+
}>;
|
|
135
|
+
/** Extend the frame in one direction. */
|
|
136
|
+
export declare function submitPan(client: MidjourneyClient, jobId: string, index: number, direction: "left" | "right" | "up" | "down", opts?: SubmitOptions & {
|
|
137
|
+
prompt?: string;
|
|
138
|
+
fraction?: number;
|
|
139
|
+
}): Promise<{
|
|
140
|
+
jobIds: string[];
|
|
141
|
+
raw: unknown;
|
|
142
|
+
}>;
|
|
143
|
+
/** Zoom out, filling the new space. 100 is no change; 200 doubles the frame. */
|
|
144
|
+
export declare function submitZoomOut(client: MidjourneyClient, jobId: string, index: number, opts?: SubmitOptions & {
|
|
145
|
+
prompt?: string;
|
|
146
|
+
zoomFactor?: number;
|
|
147
|
+
}): Promise<{
|
|
148
|
+
jobIds: string[];
|
|
149
|
+
raw: unknown;
|
|
150
|
+
}>;
|
|
151
|
+
/** Re-render one image against a new prompt, keeping its composition. */
|
|
152
|
+
export declare function submitRemix(client: MidjourneyClient, jobId: string, index: number, prompt: string, opts?: SubmitOptions & {
|
|
153
|
+
strong?: boolean;
|
|
154
|
+
}): Promise<{
|
|
155
|
+
jobIds: string[];
|
|
156
|
+
raw: unknown;
|
|
157
|
+
}>;
|
|
94
158
|
export type ListOptions = {
|
|
95
159
|
limit?: number;
|
|
96
160
|
cursor?: string;
|
package/dist/api/jobs.js
CHANGED
|
@@ -187,6 +187,130 @@ export async function submitRaw(client, jobType, extra, options = {}) {
|
|
|
187
187
|
refreshView(client, options.refresh !== false);
|
|
188
188
|
return { jobIds: extractJobIds(raw), raw };
|
|
189
189
|
}
|
|
190
|
+
/**
|
|
191
|
+
* The rest of the job types, read out of the web app's own bundle.
|
|
192
|
+
*
|
|
193
|
+
* Every shape below was extracted from the compiled client rather than guessed
|
|
194
|
+
* or clicked, so the field names are the app's own. That matters: `upscale`
|
|
195
|
+
* takes a `type`, `video` nests its source under `parentJob` with `image_num`
|
|
196
|
+
* rather than `index`, and `pan` carries a `fraction` and a `stitch` flag. None
|
|
197
|
+
* of that is inferable, and a wrong guess spends GPU time on a request that
|
|
198
|
+
* quietly does nothing.
|
|
199
|
+
*/
|
|
200
|
+
function baseBody(userId, options) {
|
|
201
|
+
return {
|
|
202
|
+
f: { mode: options.speed ?? "fast", private: options.private ?? false },
|
|
203
|
+
channelId: channelIdFor(userId),
|
|
204
|
+
metadata: {
|
|
205
|
+
isMobile: null,
|
|
206
|
+
imagePrompts: null,
|
|
207
|
+
imageReferences: null,
|
|
208
|
+
characterReferences: null,
|
|
209
|
+
depthReferences: null,
|
|
210
|
+
lightboxOpen: null,
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
async function submitShape(client, shape, options) {
|
|
215
|
+
const userId = await client.userId();
|
|
216
|
+
const body = { ...baseBody(userId, { speed: options.speed ?? client.config.defaultSpeed, ...options }), ...shape };
|
|
217
|
+
const raw = await client.request(ENDPOINTS.submit, { method: "POST", body, noRetry: true });
|
|
218
|
+
refreshView(client, options.refresh !== false);
|
|
219
|
+
return { jobIds: extractJobIds(raw), raw };
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Which upscaler a job can use, derived from the model that made it.
|
|
223
|
+
*
|
|
224
|
+
* The menu says "Subtle" and "Creative", but the wire wants a version-specific
|
|
225
|
+
* name: `v8r1_2x_subtle` for a v8.1 image, `v7_2x_creative` for a v7 one. Send
|
|
226
|
+
* the label and the request is refused. None of this is guessable, and it is
|
|
227
|
+
* why the first four attempts here were 400s.
|
|
228
|
+
*/
|
|
229
|
+
export function upscalerFor(version, style) {
|
|
230
|
+
const v = (version ?? "8.1").toLowerCase().replace(/^v/, "").trim();
|
|
231
|
+
if (v.startsWith("8.2"))
|
|
232
|
+
return `v8r2_2x_${style}`;
|
|
233
|
+
if (v.startsWith("8"))
|
|
234
|
+
return `v8r1_2x_${style}`;
|
|
235
|
+
if (v.startsWith("niji 7") || v.startsWith("7"))
|
|
236
|
+
return `v7_2x_${style}`;
|
|
237
|
+
if (v.startsWith("6.1") || v.startsWith("niji 6"))
|
|
238
|
+
return `v6r1_2x_${style}`;
|
|
239
|
+
if (v.startsWith("6"))
|
|
240
|
+
return `v6_2x_${style}`;
|
|
241
|
+
// Older lines only ever had the fixed upscalers, with no subtle or creative.
|
|
242
|
+
return `v5_2x`;
|
|
243
|
+
}
|
|
244
|
+
/** The model version a job was made with, read off the job itself. */
|
|
245
|
+
export function versionOfJob(job) {
|
|
246
|
+
const fromType = job?.jobType?.match(/^v(\d+)-(\d+)_/);
|
|
247
|
+
if (fromType)
|
|
248
|
+
return `${fromType[1]}.${fromType[2]}`;
|
|
249
|
+
const fromPrompt = job?.prompt?.match(/--v\s+(\S+)/);
|
|
250
|
+
if (fromPrompt)
|
|
251
|
+
return fromPrompt[1];
|
|
252
|
+
const niji = job?.prompt?.match(/--niji\s+(\S+)/);
|
|
253
|
+
if (niji)
|
|
254
|
+
return `niji ${niji[1]}`;
|
|
255
|
+
return undefined;
|
|
256
|
+
}
|
|
257
|
+
/** Upscale one image from a grid. `subtle` keeps it; `creative` reworks detail. */
|
|
258
|
+
export async function submitUpscale(client, jobId, index, style, options = {}) {
|
|
259
|
+
const version = options.version ?? versionOfJob(await findJob(client, jobId));
|
|
260
|
+
return submitShape(client, { t: "upscale", type: upscalerFor(version, style), id: jobId.trim(), index }, options);
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Animate one image into a video.
|
|
264
|
+
*
|
|
265
|
+
* Two things here are not guessable and both cost a rejected request to learn.
|
|
266
|
+
* The source is nested under `parentJob` as `image_num`, not the flat `index`
|
|
267
|
+
* every other job type uses. And `newPrompt` carries the image's own prompt,
|
|
268
|
+
* not a description of the motion: passing "slow push in" on its own is
|
|
269
|
+
* refused, because the field is the scene, not the movement.
|
|
270
|
+
*
|
|
271
|
+
* So a motion note is appended to the original prompt rather than replacing
|
|
272
|
+
* it, which is what the web app does when you type into its box.
|
|
273
|
+
*/
|
|
274
|
+
export async function submitVideo(client, jobId, index, opts = {}) {
|
|
275
|
+
const source = await findJob(client, jobId);
|
|
276
|
+
const original = (source?.prompt ?? "").trim();
|
|
277
|
+
const motion = opts.motion?.trim();
|
|
278
|
+
const newPrompt = motion ? `${original} ${motion}`.trim() : original;
|
|
279
|
+
return submitShape(client, {
|
|
280
|
+
t: "video",
|
|
281
|
+
videoType: `vid_1.1_i2v_${opts.resolution ?? "480"}`,
|
|
282
|
+
stitch: null,
|
|
283
|
+
newPrompt,
|
|
284
|
+
parentJob: { job_id: jobId.trim(), image_num: index },
|
|
285
|
+
animateMode: opts.mode ?? (motion ? "manual" : "auto"),
|
|
286
|
+
}, opts);
|
|
287
|
+
}
|
|
288
|
+
/** Extend the frame in one direction. */
|
|
289
|
+
export function submitPan(client, jobId, index, direction, opts = {}) {
|
|
290
|
+
return submitShape(client, {
|
|
291
|
+
t: "pan",
|
|
292
|
+
newPrompt: opts.prompt ?? "",
|
|
293
|
+
direction,
|
|
294
|
+
fraction: opts.fraction ?? 0.5,
|
|
295
|
+
stitch: true,
|
|
296
|
+
id: jobId.trim(),
|
|
297
|
+
index,
|
|
298
|
+
}, opts);
|
|
299
|
+
}
|
|
300
|
+
/** Zoom out, filling the new space. 100 is no change; 200 doubles the frame. */
|
|
301
|
+
export function submitZoomOut(client, jobId, index, opts = {}) {
|
|
302
|
+
return submitShape(client, {
|
|
303
|
+
t: "outpaint",
|
|
304
|
+
newPrompt: opts.prompt ?? "",
|
|
305
|
+
zoomFactor: opts.zoomFactor ?? 200,
|
|
306
|
+
id: jobId.trim(),
|
|
307
|
+
index,
|
|
308
|
+
}, opts);
|
|
309
|
+
}
|
|
310
|
+
/** Re-render one image against a new prompt, keeping its composition. */
|
|
311
|
+
export function submitRemix(client, jobId, index, prompt, opts = {}) {
|
|
312
|
+
return submitShape(client, { t: "remix", strong: opts.strong ?? false, newPrompt: prompt, id: jobId.trim(), index }, opts);
|
|
313
|
+
}
|
|
190
314
|
/** Recent jobs for the signed-in account. */
|
|
191
315
|
export async function listJobs(client, options = {}) {
|
|
192
316
|
const userId = options.userId ?? (await client.userId());
|