π¬ MuAPI Save Video
Downloading, Saving and Frame-Extracting
- frames
- filepath
- frame_count
Every other node in this pack hands you a URL. π¬ MuAPI Save Video is the one that turns it into a file on your disk and an IMAGE batch you can keep working with - which makes it the terminal node of essentially every MuAPI workflow you'll build.
It's also the only node in the pack with OUTPUT_NODE set, so it always runs.
Inputs
Three required fields. video_url is the STRING you wire from Text-to-Video, Image-to-Video, Video Edit, Lipsync or Extend. save_subfolder defaults to muapi_videos and lives inside ComfyUI's output directory. filename_prefix defaults to muapi.
Optional: frame_load_cap (0 means every frame), skip_first_frames, and select_every_nth. If those three names look familiar, they're the standard video-loader controls - and they're here because this node is really two tools in a trenchcoat: a downloader and a frame loader.
The download happens in Python with requests, streamed in 8KB chunks with a 300-second timeout. Filenames are de-duplicated on disk, so a repeat run writes muapi_00002.mp4 rather than clobbering the first one.
The security design, and why you shouldn't fight it
This is the most locked-down node in the pack, deliberately. It accepts only HTTPS URLs on cdn.muapi.ai, port 443 (or no port), with no credentials in the URL, and it refuses redirects:
- Any other host β "Video URL must be an HTTPS MuAPI CDN URL."
- A 3xx response β "MuAPI CDN redirects are not allowed."
That means you can't point it at a YouTube link, a tunnel to your own server, or a friend's clip host. For a node whose entire job is fetching a URL, this is the right call - an unrestricted downloader is an SSRF hole you'd be handing to whatever string lands in that widget. Just know that a URL from anywhere other than muapi's CDN will fail by design, and no amount of quoting will change it.
save_subfolder is confined the same way: it resolves under ComfyUI's output directory and anything that escapes - .., an absolute path - is rejected with "Save subfolder must remain inside the output directory." filename_prefix must be a single filename component: no /, no \, no :, no control characters, and not . or ... You're not going to hit these by accident; you'll hit them if you try to save outside output/, which the node won't do.
Outputs
frames (IMAGE) - the decoded video as a batch, which is the interesting one: frames are what a local model can consume. Feed them to an interpolation node, an upscaler, or a frame-based video model. filepath (STRING) is the absolute path to the mp4, and frame_count (INT) tells you how many frames you actually got after the skip/stride/cap maths.
When it silently gives you a black square
Everything in this node is wrapped in a try/except, and failures don't raise - they print and return (black 64Γ64 tensor, "ERROR", 0). So: mp4 saved but frames is garbage? That's OpenCV. Frame decoding uses cv2.VideoCapture, and if opencv-python isn't installed or is broken, the file downloads fine and the frame path fails soft. Check the console for [MuAPI VideoSaver] frame load error - and note that opencv-python is in the pack's requirements.txt, so a ComfyUI where that install was skipped is the usual suspect. Dependency breakage like this is the standing tax on the custom-node ecosystem - see comfyui-ecosystem.md for why it never gets fixed.
A filepath of literally "ERROR" means the download stage failed, not the frame stage. Read the printed message; it names the reason.
Install
Manager β Install via Git URL β https://github.com/SamurAIGPT/muapi-comfyui β restart. Or:
cd ComfyUI/custom_nodes
git clone https://github.com/SamurAIGPT/muapi-comfyui
pip install -r muapi-comfyui/requirements.txt
That leaves requests, Pillow, numpy, torch and opencv-python to satisfy. The first four are in any working ComfyUI; the last is the one worth verifying, since it's this node's only real dependency.
The workflow shape
Video node β this node β save plus frames. From there you've left the API behind entirely: upscale those frames locally with SeedVR2, run them through a local interpolation node, or hand them to whatever comes next. It's the same boundary the KB describes for the whole API-wrapper category - the cloud call is a stage in your graph, not a separate universe, and this node is where the two meet.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| video_url | STRING | β | |
| save_subfolder | STRING | muapi_videos | β |
| filename_prefix | STRING | muapi | β |
| frame_load_capopt | INT | 00β9999 | β |
| skip_first_framesopt | INT | 00β500 | β |
| select_every_nthopt | INT | 11β30 | β |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| frames | IMAGE | β |
| filepath | STRING | β |
| frame_count | INT | β |