- Node.js 24 or newer; an active LTS release is recommended.
mkvmergeorffmpegis optional. Install either one and add it toPATHif you need to mux separate audio and video tracks.- Bento4
mp4decryptmust be available inPATHto decrypt fMP4/CMAFSAMPLE-AES(cbcs) playlists.
npm install --global minyamiYou can also install it with Yarn:
yarn global add minyamiFor convenient playlist detection in Chrome, install the Minyami Chrome extension. Its source is available in the extension repository.
Download a playlist:
minyami "https://example.com/video.m3u8" --output "./video.ts"Useful examples:
# Use eight concurrent downloads
minyami -d "https://example.com/video.m3u8" --threads 8
# Send multiple request headers
minyami -d "https://example.com/video.m3u8" -H "Cookie: session=..." -H "User-Agent: ..."
# Download a time range
minyami -d "https://example.com/video.m3u8" --slice "45:00-53:00"
# Follow a live playlist until you stop the command
minyami -d "https://example.com/live.m3u8" --live
# Use an HTTP, HTTPS, or SOCKS5 proxy
minyami -d "https://example.com/video.m3u8" --proxy "http://127.0.0.1:1080"The download command requires a URL or local playlist path; missing input displays an error and help.
--output and --slice require string values. Invalid values are reported and omitted while other valid options remain active.
| Option | Description |
|---|---|
--help, -h |
Show help. Pass a command name to show command-specific help. |
--version |
Show the installed version. |
--download <input>, -d <input> |
Download an m3u8 URL or file. |
--threads <number> |
Set the concurrency limit. The default is 5. |
--retries <number> |
Set the maximum attempts for both source requests and download tasks. The default is 5. |
--output <path>, -o <path> |
Set the output basename. The default is ./output. |
--temp-dir <path> |
Choose the parent directory for temporary files. |
--key <key|kid:key> |
Supply an explicit HLS decryption key. One key applies to every AES-128 key URI; repeated keys map to distinct URIs in first-seen order within each Media Playlist. Multiple fMP4 SAMPLE-AES keys require kid:key. |
--cookies <cookies> |
Send cookies with download requests. |
--headers <header>, -H <header> |
Send a custom HTTP header. Repeat the option to send multiple headers. |
--live |
Follow a live playlist. |
--proxy <url> |
Use an HTTP, HTTPS, or SOCKS5 proxy. |
--no-proxy |
Ignore proxy environment variables and system proxy settings. |
--slice <start-end> |
Download a time range such as 45:00-53:00. |
--no-merge |
Keep downloaded chunks separate. |
--keep, -k |
Keep temporary files. |
--keep-encrypted-chunks |
Keep encrypted chunks after decryption. Use with --keep. |
--verbose, --debug |
Enable debug output. |
Place a JSON object in ~/.minyami/.minyamirc, ~/.minyami/.minyamirc.json, or
~/.minyami/minyami.config.json. The first readable JSON object in this order supplies defaults. Use the CLI option names in
camelCase, such as noProxy, tempDir, and keepEncryptedChunks:
{
"threads": 8,
"noProxy": true,
"verbose": true
}Explicit CLI values override file defaults before validation. The merged noProxy and verbose settings also control
proxy discovery and debug output. Use JSON booleans for flags, positive integers for threads and retries, strings for
other values, and a string or string array for headers and key. Unreadable files, malformed JSON, and non-object roots
are silently skipped; if no candidate is usable, the command proceeds without file defaults. Invalid merged option
types stop the command with an error and exit code 1.
Minyami is distributed as ESM and must be loaded with import rather than CommonJS require().
Download an archive playlist:
import { createArchiveDownloader } from "minyami";
const downloader = createArchiveDownloader("https://example.com/archive.m3u8", {
output: "./archive.ts",
threads: 8,
});
downloader.on("chunk-downloaded", (chunk) => {
console.log(chunk);
});
await downloader.download();Library callers pass parsed explicit keys as HLSExplicitKey objects, for example explicitKeys: [{ key }] or
explicitKeys: [{ kid, key }]. The CLI accepts the equivalent compact key and kid:key forms. For AES-128,
one explicit key applies to every key URI; multiple keys are assigned to distinct key URIs in first-seen order within
each Media Playlist and retain those assignments across live refreshes. Multiple fMP4 SAMPLE-AES keys are selected by
KID instead.
For a live playlist, create a live downloader and call stop() when you want to finish:
import { createLiveDownloader } from "minyami";
const downloader = createLiveDownloader("https://example.com/live.m3u8", {
output: "./live.ts",
});
setTimeout(() => downloader.stop(), 60_000);
await downloader.download();Use streamSelector to choose tracks from a master playlist. Return tracks from one of the provided options, or return undefined to cancel the download:
const downloader = createArchiveDownloader("https://example.com/master.m3u8", {
streamSelector: (catalog) =>
catalog.options.find((option) =>
option.tracks.some((track) => track.type === "video" && track.height === 720)
)?.tracks,
});
await downloader.download();When streamSelector is omitted, the library selects all tracks from the highest-bandwidth option.
No.
Pass --proxy, or set HTTP_PROXY, HTTPS_PROXY, or ALL_PROXY. On Windows, Minyami can also use the system proxy settings. Pass --no-proxy to ignore all of these settings.
Pass --temp-dir <path>. By default, Minyami creates a minyami_<timestamp>_<random> directory under the current working directory.
Repeat -H or --headers:
minyami -d "https://example.com/video.m3u8" -H "Cookie: ..." --headers "User-Agent: ..."GPLv3. © 2018-2025 Eridanus Sora, member of MeowSound Idols.