CLI Usage
Tip
TMDB-based filename tokens (%(tmdb_id), %(original_title), etc.) and poster embedding
require a TMDB API key — see TMDB API Key for setup.
Basic Commands
# Show help and available sites
python manual.py -h
# Search and download
python manual.py -i streamingcommunity --search "interstellar"
# Auto-download the first result (--item 0 picks the first result, 0-based)
python manual.py -i streamingcommunity --search "interstellar" --item 0
# Select a specific result by index (0-based) instead of the first
python manual.py -i streamingcommunity --search "interstellar" --item 2
# Use a site by its index number
python manual.py -i 0 --search "interstellar"
# Skip TS/CAM releases (StreamingCommunity only)
python manual.py -i streamingcommunity --search "interstellar" --skip-ts
# Disable the log file for this run
python manual.py -i streamingcommunity --search "interstellar" --no-log
Series Selection
Use --season and --episode to skip interactive prompts:
# Specific episode
python manual.py -i streamingcommunity --search "breaking bad" --item 0 --season 1 --episode 3
# Range of episodes
python manual.py -i streamingcommunity --search "breaking bad" --item 0 --season 1 --episode "1-5"
# All episodes of a season
python manual.py -i streamingcommunity --search "breaking bad" --item 0 --season 1 --episode "*"
# All episodes of all seasons
python manual.py -i streamingcommunity --search "breaking bad" --item 0 --season "*"
# Multiple seasons
python manual.py -i streamingcommunity --search "breaking bad" --item 0 --season "1-3"
Year Filter
# Exact year
python manual.py -i streamingcommunity --search "dune" --year 2021
# Year range
python manual.py -i streamingcommunity --search "batman" --year "1990-2015"
Stream Track Overrides
# Video resolution
python manual.py -i streamingcommunity --search "interstellar" -sv 1080
# Audio language
python manual.py -i streamingcommunity --search "interstellar" -sa "eng"
# Subtitles
python manual.py -i streamingcommunity --search "interstellar" -ss "eng"
# Only the forced subtitle track
python manual.py -i streamingcommunity --search "interstellar" -ss "ita_forced"
# Skip the whole download if the requested filter matches no track
python manual.py -i streamingcommunity --search "interstellar" -sa "deu" --skip-no-match
# Output container (overrides PROCESS.extension from config.json for this run)
python manual.py -i streamingcommunity --search "interstellar" --extension mp4
See Stream Selection Filters for the full
-sv/-sa/-ss filter syntax (resolution, codec, bitrate, language, Dolby Vision companion).
Console Behaviour Override
# Keep console open (loop mode)
python manual.py --close-console false
# Close console after download
python manual.py -i streamingcommunity --search "interstellar" --close-console true
Proxy
# Use the configured proxy for everything (default scope)
python manual.py -i streamingcommunity --search "interstellar" --use_proxy
# Proxy only the downloads (Velora), scrape directly
python manual.py -i streamingcommunity --search "interstellar" --use_proxy --proxy-scope down
# Proxy only the scraping, download directly
python manual.py -i streamingcommunity --search "interstellar" --use_proxy --proxy-scope scrap
Progress Output
By default the download shows live bars redrawn in place.
# One line per track every 5 seconds (and on every phase change / completion), e.g.
# Vid [H.264] 720p 2.4 Mbps 28% 290.2M / 1012.7M 65.27M/s ETA 00:11
python manual.py -i streamingcommunity --search "interstellar" --plain-progress
# ...every 2 seconds
python manual.py -i streamingcommunity --search "interstellar" --plain-progress --progress-interval 2
# No progress output at all
python manual.py -i streamingcommunity --search "interstellar" --no-progress
Metadata Sidecars (.nfo + artwork)
Write the files Jellyfin, Emby and Kodi use to identify a download (<name>.nfo plus -poster.jpg for a film or
-thumb.jpg for an episode). Only written for a reliable match; off by default (DOWNLOAD.write_sidecars).
See Metadata Providers.
# Enable for this run, with the default providers (TMDB, then IMDb)
python manual.py -i streamingcommunity --search "interstellar" --sidecars
# Only IMDb (free, no API key needed)
python manual.py -i streamingcommunity --search "interstellar" --sidecars --metadata-provider imdb
# TheTVDB first, TMDB as fallback (needs TVDB_API_KEY or Provider.tvdb in login.json)
python manual.py -i streamingcommunity --search "interstellar" --sidecars --metadata-provider tvdb,tmdb
# Disable for this run even if enabled in config.json
python manual.py -i streamingcommunity --search "interstellar" --no-sidecars
Show Dependency Paths
python manual.py --dep
Direct Download by URL (--down)
Download a stream directly from its URL, bypassing site search entirely. The stream type is
auto-detected (MP4 / HLS / DASH / ISM) or can be forced with --type.
# Simple MP4 / auto-detected stream
python manual.py --down "https://example.com/video.mp4" -o "./Video/clip.mp4"
# HLS with a known decryption key
python manual.py --down "https://example.com/master.m3u8" --type hls \
--key "<KID>:<KEY>" -o "./Video/movie.mkv"
# DASH with a DRM license server (Widevine)
python manual.py --down "https://example.com/manifest.mpd" --type dash \
--license-url "https://example.com/wv/license" --drm widevine \
--headers "Authorization: Bearer <token>" -o "./Video/movie.mkv"
# DASH with a DRM license server that also needs its own HTTP header (repeatable, like --headers)
python manual.py --down "https://example.com/manifest.mpd" --type dash \
--license-url "https://example.com/wv/license" --drm widevine \
--license-headers "Authorization: Bearer <token>" -o "./Video/movie.mkv"
# Grab just a clip: segments 10-50, or the 00:01:00-00:05:00 time range
python manual.py --down "https://example.com/master.m3u8" --type hls \
--max-segments "10-50" -o "./Video/clip.mkv"
python manual.py --down "https://example.com/master.m3u8" --type hls \
--max-time "00:01:00-00:05:00" -o "./Video/clip.mkv"
Custom JSON Manifest
--down also accepts a local path or URL pointing at a custom JSON manifest — a plain
stream description for sources that don't expose a real HLS/DASH/ISM manifest. It's
auto-detected when the target is a .json file/URL containing the "vibravid_manifest"
marker, no --type needed.
{
"vibravid_manifest": true,
"base_url": "https://cdn.example.com/movie/",
"duration": 5410.0,
"tracks": [
{
"type": "video", "id": "v1", "codecs": "avc1.640028",
"width": 1920, "height": 1080, "bitrate": 4500000,
"init": "init_video.mp4",
"segments": {"template": "chunk_video_$Number$.m4s", "start": 1, "end": 1352, "duration": 4.0}
},
{
"type": "audio", "id": "a1", "language": "eng", "codecs": "mp4a.40.2",
"init": "init_audio.mp4",
"segments": {"list": ["seg0.m4s", "seg1.m4s", "seg2.m4s"]}
}
]
}
python manual.py --down "https://example.com/manifest.json" -o "./Video/movie.mkv"
python manual.py --down "./local_manifest.json" -o "./Video/movie.mkv"
Segment modes for a track's segments field:
| Mode | Fields | Behaviour |
|---|---|---|
list |
array of URLs, or objects with url/size/duration/range |
explicit segment list |
template |
template, start, step (or duration), end (or count) |
DASH-style $Number$ / $Time$ / $RepresentationID$ placeholder expansion |
ranges / chunk |
url + explicit ranges array, or chunk + size to auto-split |
byte-range segments carved out of a single file |
init accepts a URL string, an object (url, range), or inline base64 (data) for the
initialization segment. Placeholders support zero-padding, e.g. $Number%05d$; $$ escapes
a literal $.
Batch Replay from a TRACKS_JSON file (--down-json)
--down-json runs every entry's cmd from a TRACKS_JSON debug file (see
debug_track_json in Configuration) in sequence, instead of a single
--down invocation:
python manual.py --down-json "./debug/tracks_20260821.json"
Attaching metadata to a direct download (--meta-*)
A plain --down has no title/type/season/episode context, so title-dependent hooks and the
Vault upload/lookup are skipped by default for it. Pass --meta-* flags to attach that context
so those still work:
python manual.py --down "https://example.com/master.m3u8" --type hls \
--key "<KID>:<KEY>" -o "./Video/Movie (2024)/movie.mkv" \
--meta-title "Movie Name" --meta-type Film --meta-site streamingcommunity
# TV episode
python manual.py --down "https://example.com/master.m3u8" --type hls \
--key "<KID>:<KEY>" -o "./Video/Show/Season 01/episode.mkv" \
--meta-title "Show Name" --meta-type TV --meta-season 1 --meta-episode 3
--resolve-only sets these automatically on the --down entry it produces, so this is mostly
needed when hand-building a --down/--down-json invocation yourself.
Direct Download via yt-dlp (--yt-dlp)
Download from any site yt-dlp supports bypassing site search entirely — separate from --down, which is for direct HLS/DASH/ISM/MP4 URLs.
# Basic download
python manual.py --yt-dlp "https://www.youtube.com/watch?v=..." -o "./Video/clip.mp4"
# Pick a specific format instead of the default bestvideo+bestaudio/best
python manual.py --yt-dlp "https://www.youtube.com/watch?v=..." --format "best[height<=720]"
# List available formats and exit, or pick one interactively
python manual.py --yt-dlp "https://www.youtube.com/watch?v=..." --list-formats
python manual.py --yt-dlp "https://www.youtube.com/watch?v=..." --interactive-format
# Extract audio only
python manual.py --yt-dlp "https://www.youtube.com/watch?v=..." --extract-audio \
--audio-format mp3 --audio-quality 0
# Subtitles
python manual.py --yt-dlp "https://www.youtube.com/watch?v=..." --write-subs --sub-langs it,en
python manual.py --yt-dlp "https://www.youtube.com/watch?v=..." --write-auto-subs
# Only the first N entries of a playlist
python manual.py --yt-dlp "https://www.youtube.com/playlist?list=..." --playlist-end 5
| Flag | Effect |
|---|---|
--yt-dlp <URL> |
Download this URL with yt-dlp instead of the site-search/--down flow |
--format <SPEC> |
yt-dlp format selector (default: bestvideo+bestaudio/best) |
--list-formats |
List available formats for the URL and exit |
--interactive-format |
Show available formats and prompt for the format ID before downloading |
--extract-audio |
Extract audio only |
--audio-format <FORMAT> |
Audio format for extraction (e.g. mp3, m4a, wav, opus) |
--audio-quality <QUALITY> |
Audio quality for extraction (e.g. 0, 5, 8k) |
--playlist-end <N> |
Only process the first N entries of a playlist |
--sub-langs <LANGS> |
Comma-separated subtitle languages (e.g. it,en) |
--write-subs |
Write subtitles |
--write-auto-subs |
Write auto-generated subtitles |
Advanced Options
| Flag | Effect |
|---|---|
--use-curl-cffi |
Download segments via curl_cffi (browser TLS impersonation) instead of Velora — for sites where individual segments are Cloudflare-protected |
--http-version {1.1,2,3} |
Force the HTTP protocol version used for requests instead of letting the client negotiate it |
-o, --output <PATH> |
Output file path for --down/--yt-dlp direct downloads |
--amazon-music-login |
Log in to Amazon Music (stores credentials for future runs) |
--amazon-music-logout |
Clear stored Amazon Music login credentials |
--no-vault-cache |
Bypass the DRM key vault cache; force a fresh CDM license request every run (for dynamic/time-sensitive tokens) |
--no-decrypt |
Debug switch: don't decrypt at all (neither the in-flight per-segment path nor the post-download pass) |
--no-livemux |
Disable the streaming-mux fast path for this run, always falling back to the normal post-download join_media() pass. On by default |
--livemux |
Force-enable the streaming-mux fast path for this run even if the current service does not opt in via _live_mux = True. Off by default |
--no-concurrent |
Download video, audio and subtitles sequentially instead of simultaneously for this run. Concurrent download is on by default |
--skip-no-match |
Skip the whole download if -sv/-sa/-ss matches no track, instead of falling back to the best available one |
--log-decryptor-output |
Write flux's own stdout+stderr lines to the log file as they run, tagged with the engine name (e.g. [FLUX]) instead of [INFO] |
--abc |
Anonymize printed KID:KEY pairs in the console/log, masking alternating characters with ? |
--hls-method AES_128\|NONE |
Override the HLS segment encryption method, ignoring the manifest's own #EXT-X-KEY tag (or supplying one when it has none). NONE treats every segment as already clear; AES_128 forces AES-128-CBC (pair with --hls-key/--hls-iv) |
--hls-key <HEX\|BASE64\|FILE> |
Raw AES-128 key to use instead of fetching URI= from the manifest's #EXT-X-KEY tag |
--hls-iv <HEX> |
IV to use instead of the manifest's IV=0x... (or the implicit per-segment IV) |
--skip-content-check |
Skip the preflight HEAD content-type check for MP4 direct downloads (--type mp4) — needed for single-use download URLs where a HEAD request consumes the link |
--skip-sanitize |
Use the -o output path verbatim (MP4/HLS/DASH/ISM direct downloads), skipping path sanitization (transliteration of non-ASCII characters) |
--no-manifest-info |
Don't print the parsed manifest/streams table |
--binary-update |
Check FFmpeg/Flux/Packager/dovi_tool/MKVToolNix/Velora against AstraeLabs/Binary and re-download whichever is outdated |
--resolve-only |
Resolve and cache the manifest (keys, license, playlist) without actually downloading — pairs with --down-json/the queue to download later without re-resolving |
--tui |
Launch the Textual terminal UI instead of the plain CLI flow |
-UP, --update |
Auto-update to the latest release (binary builds only) |
--version |
Print the installed version and exit |
# Resolve now, download later: cache the manifest/keys without downloading
python manual.py -i streamingcommunity --search "interstellar" --item 0 --resolve-only
# Launch the TUI instead of the classic prompt-driven flow
python manual.py --tui
# Manual AES-128 override, e.g. for a manifest missing its own #EXT-X-KEY tag
python manual.py --down "https://example.com/master.m3u8" --type hls \
--hls-method AES_128 \
--hls-key "0011223344556677889900112233445566" \
--hls-iv "00000000000000000000000000000001" \
-o "./Video/clip.mkv"
Download Queue (--queue-*)
# Queue instead of downloading now
python manual.py -i streamingcommunity --search "interstellar" --item 0 --queue-add
python manual.py --down "https://example.com/movie.mkv" -o "./Video/movie.mkv" --queue-add
# Inspect / manage the queue
python manual.py --queue-list
python manual.py --queue-remove <ID>
python manual.py --queue-clear
# Process every pending (or interrupted) item in order
python manual.py --queue-run
Note
Only invocations that would already complete without any prompt can be queued; anything
ambiguous (e.g. --global, or a site search with no --item) is rejected at
enqueue time.
Items enqueued together share one auto-generated queue name (e.g. 20260723-152525, shown
by --queue-list). Most queue commands accept that name to target just one batch instead of
every queue, and a run can be further narrowed to specific item ids:
# Target one specific batch
python manual.py --queue-run 20260723-152525
python manual.py --queue-list 20260723-152525
python manual.py --queue-clear 20260723-152525
# Restrict a run to specific item ids (as shown by --queue-list)
python manual.py --queue-run --queue-ids abc12345,def67890
# Interactively pick which queue to run from a numbered list
python manual.py --queue-select
Global Search
# Global search
python manual.py --global -s "cars"
# Filter by category
python manual.py --category 1 # Anime
python manual.py --category 2 # Movies & Series
python manual.py --category 3 # Series only
python manual.py --category 4 # Movies only