VOD2strm is a high-reliability Python exporter for converting your Dispatcharr VOD library into a clean filesystem of:
*.strmstreaming pointer files*.nfometadata files- Posters & fanart (when available)
- Deterministic folder structures
- Fully cached provider-info + XC fallback metadata
Compatible with Emby, Jellyfin, Plex, and any STRM/NFO aware media system.
Everything is driven via the Dispatcharr API — no playlist parsing, no M3U processing.
flowchart TD
A[Dispatcharr API] -->|provider-info| B[Normalize Provider Info]
B -->|Episodes OK| C[STRM + NFO Builder]
B -->|Missing Episodes| D[XC get_series_info]
D --> E[Normalize XC Episodes]
E --> F[Merged Episode Model]
C --> G[Filesystem Export]
F --> C
- Full STRM + NFO generation
- Proper movie folder layout
- Cached artwork downloads
- Clean title normalization
- Proxy-friendly stream URLs
- Series → Seasons → Episodes filesystem
tvshow.nfo+ per-episode*.nfo- Normalised episode objects (Dispatcharr & XC unified)
- Cached provider-info per account
- Automatic XC fallback when needed
- Correct ordering & deduplication
- Each account has isolated cache under
cache/<account>/ - Cached:
- provider-info
- XC get_series_info
- artwork
- Re-runs are fast — only changed episodes are processed
- DRY-RUN mode
- CLEAR_CACHE mode
- LOG_LEVEL (
DEBUG,INFO,WARN,ERROR) - Account filtering
- Directory-agnostic (
SCRIPT_DIR)
Dispatcharr currently has an outstanding bug where:
GET /api/vod/series/<id>/provider-info/?include_episodes=true
often returns no episodes, or hits an internal:
500 Internal Server Error
Until this is fixed, VOD2strm performs a safe, minimal XC fallback.
- Call Dispatcharr provider-info
- If episodes exist → use them
- If missing episodes → fallback triggers (if enabled)
- XC endpoint called:
/player_api.php?username=<USER>&password=<PASS>&action=get_series_info&series_id=<ID> - XC episodes are normalised
- Data merged (primary: Dispatcharr → fallback: XC)
- Export proceeds normally
Add to VOD2strm_vars.sh:
export ENABLE_XC_EPISODE_FALLBACK="false"Or at runtime:
ENABLE_XC_EPISODE_FALLBACK=false ./VOD2strm.pyMovies/
<Category>/
<Title (Year)>/
movie.nfo
poster.jpg
fanart.jpg
movie.strm
Series/
<Category>/
<Show Name>/
tvshow.nfo
poster.jpg
fanart.jpg
Season 01/
S01E01 - Episode Title.strm
S01E01 - Episode Title.nfo
Season 02/
...
Category fallback priority:
genre → category_name → "Unsorted"
| Variable | Description |
|---|---|
DISPATCHARR_URL |
Base Dispatcharr URL |
API_TOKEN |
API key |
OUTPUT_ROOT |
Root export directory |
CACHE_DIR |
Override cache directory |
LOG_LEVEL |
DEBUG / INFO / WARN / ERROR |
CLEAR_CACHE |
true = wipe cache before run |
DRY_RUN |
true = do not write files |
ENABLE_XC_EPISODE_FALLBACK |
true/false toggle |
ACCOUNT_FILTERS |
Process only named accounts |
Normal:
./VOD2strm.py
Verbose:
LOG_LEVEL=INFO ./VOD2strm.py
Dry run:
DRY_RUN=true ./VOD2strm.py
Clear caches:
CLEAR_CACHE=true ./VOD2strm.py
Source vars file:
source ./VOD2strm_vars.sh
./VOD2strm.py
| Stage | Time |
|---|---|
| Movies fetch | ~180s |
| Series fetch | ~45s |
| Exported | ~17,500 movies / ~4,200 series / 75k+ episodes |
| Issue | Status |
|---|---|
Dispatcharr /provider-info episodes bug |
Mitigated by fallback |
| XC throttling | Auto-retry + caching |
| Missing artwork | Planned |
| Minimal NFO | Being expanded |
- 0.9.x — Current builds, includes XC fallback
- 1.0.0 — Remove fallback once Dispatcharr fixes episode API
- 1.x — Performance, metadata expansion, async options
PRs welcome once public.
Please open issues for:
- CI/CD
- Provider inconsistencies
- NFO schema improvements
- Large library performance tuning
Private homelab utility — no warranty.