Skip to main content

Download content from streaming platforms

Project description

PyPI Version Sponsor

Windows macOS Linux

โšก Quick Start: pip install VibraVid && VibraVid

๐ŸŒ Language / Lingua

๐Ÿ‡ฌ๐Ÿ‡ง English | ๐Ÿ‡ฎ๐Ÿ‡น Italiano


๐Ÿ“– Table of Contents


Installation

Option 1 โ€” PyPI (recommended)

pip install VibraVid
VibraVid

Option 2 โ€” uv

uv tool install VibraVid
VibraVid

Option 3 โ€” Manual Clone

git clone https://github.com/AstraeLabs/VibraVid.git
cd VibraVid

Then install and run with either pip or uv:

pip:

pip install -r requirements.txt   # install
python manual.py                  # run
pip install -r requirements.txt --upgrade  # sync deps

uv:

uv sync              # install
uv run manual.py     # run
uv sync --upgrade    # sync deps

Option 4 โ€” Unraid

You can find the app in the Community Application

Additional Documentation

  • ๐Ÿ“ Login Guide โ€” Authentication for supported services
  • ๐Ÿ–ฅ๏ธ NAS Deployment Guide โ€” Docker setup on Synology, TrueNAS, and other NAS devices

Quick Start

# PyPI or uv install
VibraVid

# Manual clone
python manual.py

Update

Binary (Windows / macOS / Linux)

VibraVid -UP

PyPI

pip install VibraVid --upgrade

uv

uv tool upgrade VibraVid

Manual clone

git fetch origin
git reset --hard origin/main

If the folder is not yet an initialized Git repository:

git init
git remote add origin https://github.com/AstraeLabs/VibraVid.git
git fetch origin
git reset --hard origin/main

โš ๏ธ Folders ignored by .gitignore (e.g. Video/) will not be deleted.

Downloaders

Type Description Example
HLS HTTP Live Streaming (m3u8) View example
MP4 Direct MP4 download View example
DASH MPEG-DASH with DRM bypass* View example
ISM Smooth Streaming with DRM bypass* View example

*DASH with DRM bypass: Requires a valid L3\L2\L1\SL3000\SL2000 CDM (Content Decryption Module). This project does not provide or facilitate obtaining CDMs. Users must ensure compliance with applicable laws.


Configuration

All settings live in config.json. The sections below cover each configuration block.

DEFAULT

{
  "DEFAULT": {
    "debug_track_json": false,
    "log_level": "INFO",
    "close_console": true,
    "show_message": false,
    "fetch_domain_online": true,
    "auto_update_check": true,
    "imp_service": ["default"],
    "installation": "essential"
  }
}
Key Default Description
close_console true Automatically close the console after download completes
debug_track_json false Log a TRACKS_JSON payload with selected tracks, keys, and manifest metadata โ€” useful for debugging stream selection
log_level "INFO" Logging verbosity. Accepts standard Python values: DEBUG, INFO, WARNING, ERROR, CRITICAL
show_message false Show the startup banner and clear the console before printing it
fetch_domain_online true Automatically fetch the latest domains from GitHub
auto_update_check true Notify you at startup when a new VibraVid version is available
imp_service ["default"] Service source paths to load site modules from. "default" loads all built-in sites. Add absolute paths to directories containing custom site modules โ€” each must have __init__.py defining indice and _useFor. Custom modules take precedence over built-ins with the same name.
installation "essential" Controls which bundled binaries are auto-downloaded at setup: none skips all, essential downloads Bento4, FFmpeg, and Velora, full also adds Dovi Tool and MKVToolNix

Custom imp_service example:

"imp_service": ["default", "/home/user/my_custom_sites"]

OUTPUT

{
  "OUTPUT": {
    "root_path": "Video",
    "movie_folder_name": "Movie",
    "serie_folder_name": "Serie",
    "anime_folder_name": "Anime",
    "movie_format": "%(title_name) (%(title_year))/%(title_name) (%(title_year))",
    "episode_format": "%(series_name)/S%(season:02d)/%(episode_name) S%(season:02d)E%(episode:02d)"
  }
}

root_path โ€” Base directory where videos are saved.

  • Windows: C:\\MyLibrary\\Folder or \\\\MyServer\\Share
  • Linux/macOS: Desktop/MyLibrary/Folder
  • Docker / NAS: set the VIBRAVID_OUTPUT_ROOT environment variable instead of editing config.json โ€” the value is applied at startup and overrides this field without touching the persisted config file. Example: VIBRAVID_OUTPUT_ROOT=/app/Video (container path matching the bind-mount target).

movie_folder_name, serie_folder_name, anime_folder_name โ€” Subfolder names for each content type (defaults: "Movie", "Serie", "Anime"). All support the %{site_name} placeholder:

"Movie/%{site_name}"  โ†’  "Movie/Crunchyroll"
"Serie/%{site_name}"  โ†’  "Serie/Crunchyroll"

Movie Format

Default: "%(title_name) (%(title_year))/%(title_name) (%(title_year))"

%(title_name) (%(title_year))/   โ†’  folder    Inception (2010)/
%(title_name) (%(title_year))    โ†’  filename  Inception (2010).mkv
Variable Description
%(title_name) Movie title
%(title_name_slug) Movie title as slug
%(title_year) Release year (omitted if unavailable)
%(quality) Video resolution
%(language) Audio languages
%(video_codec) Video codec
%(audio_codec) Audio codec

Episode Format

Default: "%(series_name)/S%(season:02d)/%(episode_name) S%(season:02d)E%(episode:02d)"

%(series_name)/     โ†’  series folder   Breaking Bad/
S%(season:02d)/     โ†’  season folder   S01/
%(episode_name)...  โ†’  filename        Pilot S01E05.mkv
Variable Description
%(series_name) Series name
%(series_name_slug) Series name as slug
%(series_year) Series release year
%(season:FORMAT) Season number with inline padding (see below)
%(episode:FORMAT) Episode number with inline padding (see below)
%(episode_name) Episode title (sanitized)
%(episode_name_slug) Episode title as slug
%(quality) Video resolution
%(language) Audio languages
%(video_codec) Video codec
%(audio_codec) Audio codec

Inline padding syntax (for season and episode):

Token Result (n=1) Description
%(season:02d) 01 Zero-pad to 2 digits
%(season:03d) 001 Zero-pad to 3 digits
%(season:d) 1 No padding

DOWNLOAD

{
  "DOWNLOAD": {
    "auto_select": true,
    "delay_after_download": 1,
    "skip_download": false,
    "thread_count": 12,
    "concurrent_download": true,
    "select_video": "1920",
    "select_audio": "ita|Ita",
    "select_subtitle": "ita|eng|Ita|Eng",
    "cleanup_tmp_folder": true,
    "engine": "ffmpeg"
  }
}

Performance Settings

Key Default Description
auto_select true Automatically select streams based on filters. When false, enables interactive track selection before download
delay_after_download 1 Delay (seconds) applied after each movie or episode download
skip_download false Skip the download step and process existing files
thread_count 12 Number of concurrent segment requests for a single stream
concurrent_download true Download video, audio, and subtitles simultaneously
cleanup_tmp_folder true Remove temporary files after download
engine "ffmpeg" Muxing engine used to combine video, audio and subtitle tracks. ffmpeg, mkvmerge requires a full installation

Stream Selection Filters

Use select_video, select_audio, and select_subtitle to control which tracks are downloaded.

Video (select_video):

Value Description
"best" Best available resolution
"worst" Worst available resolution
"1080" Exact height (falls back to worst if not found)
"1080,H265" Height + codec constraint
"1080|best" Height with fallback to best
"1080|best,H265" Height + codec with fallback to best
"false" Skip video

Audio (select_audio):

Value Description If not found
"best" Best bitrate per language Selects best across all
"worst" Worst bitrate per language Selects worst across all
"all" All audio tracks Downloads all
"default" Streams marked as default DROP
"non-default" Streams NOT marked as default DROP
"ita" Italian audio DROP
"ita|it" Pipe-separated language codes DROP if none found
"ita,MP4A" Language + codec DROP if combination not found
"ita|best" Language with fallback to best Fallback to best
"ita|best,AAC" Language + codec with fallback Fallback to best
"false" Skip audio โ€”

Subtitle (select_subtitle):

Value Description
"all" All subtitles
"default" Streams marked as default
"non-default" Streams NOT marked as default
"ita|eng" Pipe-separated language codes
"ita_forced" Language with flag (forced, cc, sdh)
"ita_forced|eng_cc" Multiple languages with flags
"false" Skip subtitles

PROCESS (Post-Processing)

{
  "PROCESS": {
    "use_gpu": false,
    "param_video": ["-c:v", "libx265", "-crf", "28", "-preset", "medium"],
    "param_audio": ["-c:a", "libopus", "-b:a", "128k"],
    "param_final": ["-c", "copy"],
    "audio_order": ["ita", "eng"],
    "subtitle_order": ["ita", "eng"],
    "merge_audio": true,
    "merge_subtitle": true,
    "subtitle_disposition_language": "ita_forced",
    "extension": "mkv"
  }
}
Key Default Description
use_gpu false Enable hardware acceleration. GPU type is auto-detected at runtime: cuda (NVIDIA), qsv (Intel), vaapi (AMD)
param_video H.265/HEVC FFmpeg video encoding parameters, e.g. ["-c:v", "libx265", "-crf", "28", "-preset", "medium"]
param_audio Opus 128k FFmpeg audio encoding parameters, e.g. ["-c:a", "libopus", "-b:a", "128k"]
param_final ["-c", "copy"] Final FFmpeg parameters. When set, takes full precedence over param_video and param_audio
audio_order โ€” Order of audio tracks in the output, e.g. ["ita", "eng"]
subtitle_order โ€” Order of subtitle tracks in the output, e.g. ["ita", "eng"]
merge_audio true Merge all audio tracks into a single output file
merge_subtitle true Merge all subtitle tracks into a single output file
subtitle_disposition_language โ€” Mark a specific subtitle track as default/forced
extension "mkv" Output container format: "mkv" or "mp4"

force_subtitle โ€” Controls how subtitles are handled before remuxing:

Value Behaviour
"auto" (default) Subtitles are renamed/converted based on their detected format. VTT files are sanitized (unmatched < replaced) to prevent data loss when muxed as SRT
"copy" No conversion or renaming โ€” the original file is muxed as-is. Also skips VTT sanitization
"srt" / "vtt" / "ass" Force-convert all subtitles to the specified format using FFmpeg, with sanitization applied for vtt

See VibraVid/core/processors/helper/ex_sub.py for conversion logic.


REQUESTS

{
  "REQUESTS": {
    "timeout": 30,
    "max_retry": 10,
    "use_proxy": false,
    "proxy": {
      "http": "http://localhost:8888",
      "https": "http://localhost:8888"
    }
  }
}
Key Default Description
timeout 30 Request timeout in seconds
max_retry 10 Maximum retry attempts for failed requests
use_proxy false Enable proxy support for HTTP requests
proxy.http โ€” HTTP proxy URL
proxy.https โ€” HTTPS proxy URL

ARR

The ARR block enables VibraVid to work as an automation layer between Seerr/Jellyseerr, Sonarr, Radarr, and the final media library. When enabled, VibraVid polls Sonarr/Radarr for missing media, receives webhook events, downloads through its provider pipeline, and reports the resulting files back so that Sonarr/Radarr can import them.

The ARR integration requires the VibraVid web GUI to be running. All polling loops, webhook listeners, and download workers are managed by the Django application server. The CLI (vibraNid / python -m VibraVid) does not start the ARR stack.

Configuration reference

{
  "ARR": {
    "enabled": false,
    "enable_polling": false,
    "enable_seerr_webhook": false,
    "enable_sonarr_webhook": false,
    "enable_radarr_webhook": false,
    "polling_interval": 300,
    "full_resync_interval": 21600,
    "max_concurrent_downloads": 1,
    "webhook_priority_enabled": true,
    "native_webhook_priority_window_seconds": 120,
    "seerr_fallback_delay_seconds": 20,
    "download_italian_anime_default": true,
    "provider_fallback": ["streamingcommunity", "animeunity"],
    "path_mapping": {},
    "sonarr": { "url": "", "api_key": "" },
    "radarr": { "url": "", "api_key": "" },
    "seerr": { "webhook_secret": "" },
    "sonarr_webhook": { "webhook_secret": "" },
    "radarr_webhook": { "webhook_secret": "" }
  }
}
Key Default Description
enabled false Enables the ARR integration globally
enable_polling false Periodically scans Sonarr/Radarr for missing media
enable_seerr_webhook false Enables the Seerr/Jellyseerr webhook endpoint
enable_sonarr_webhook false Enables the Sonarr native webhook endpoint
enable_radarr_webhook false Enables the Radarr native webhook endpoint
polling_interval 300 Seconds between incremental polling cycles
full_resync_interval 21600 Seconds between full reconciliation syncs
max_concurrent_downloads 1 Maximum parallel ARR-triggered downloads
webhook_priority_enabled true Native Sonarr/Radarr webhooks take priority over Seerr to avoid duplicates
native_webhook_priority_window_seconds 120 Dedup window for near-simultaneous webhook events
seerr_fallback_delay_seconds 20 Delay before processing a Seerr event when a native webhook may follow
download_italian_anime_default true When an anime provider returns both an original and an (ITA) dubbed version, prefer the Italian dub
provider_fallback [] Ordered list of providers tried in sequence when the primary provider finds no match. If empty, streamingcommunity is the built-in default
path_mapping {} Translates VibraVid host paths to the paths seen by Radarr/Sonarr containers. Leave empty when both services share the same filesystem view
sonarr.url โ€” Base URL of the Sonarr instance, e.g. http://sonarr:8989
sonarr.api_key โ€” Sonarr API key
radarr.url โ€” Base URL of the Radarr instance, e.g. http://radarr:7878
radarr.api_key โ€” Radarr API key
seerr.webhook_secret โ€” Secret expected in Seerr/Jellyseerr webhook requests
sonarr_webhook.webhook_secret โ€” Secret expected in Sonarr webhook requests
radarr_webhook.webhook_secret โ€” Secret expected in Radarr webhook requests

All ARR settings can also be edited directly from the VibraVid web GUI under Settings โ†’ Configuration editor, without touching config.json manually.

These keys can also be set via environment variables (useful in Docker):

USE_ARR_SERVICES=true
SONARR_URL=http://sonarr:8989
SONARR_API_KEY=your-key
RADARR_URL=http://radarr:7878
RADARR_API_KEY=your-key
SEERR_WEBHOOK_SECRET=your-secret
SONARR_WEBHOOK_SECRET=your-secret
RADARR_WEBHOOK_SECRET=your-secret

Webhook setup

VibraVid exposes one webhook endpoint per ARR application. Add one connection only per app โ€” adding multiple webhooks for the same app causes duplicate processing.

Radarr โ†’ Settings โ†’ Connect โ†’ Webhook

Field Value
URL http://<vibravid-host>:<port>/api/arr/webhook/radarr/
Triggers On Movie Added, On Movie File Delete
Secret any value mirrored in radarr_webhook.webhook_secret

Sonarr โ†’ Settings โ†’ Connect โ†’ Webhook

Field Value
URL http://<vibravid-host>:<port>/api/arr/webhook/sonarr/
Triggers On Series Add, On Episode File Delete
Secret any value mirrored in sonarr_webhook.webhook_secret

Then enable in config.json:

"enable_sonarr_webhook": true,
"enable_radarr_webhook": true

Webhooks and polling can be used together: webhooks trigger an immediate download when media is added, polling acts as a safety net for items that arrive without a webhook event.

Provider selection

VibraVid determines which provider to use for each item through two mechanisms โ€” you can use one or both.

Method 1 โ€” Per-item tag (advanced, requires tagging each title)

Add a tag directly to the movie or series in Sonarr/Radarr using the format provider-<site>. VibraVid reads the tag at download time and uses that provider regardless of the fallback list. This is useful when specific titles are only available on a particular service.

Tags are created in Sonarr/Radarr under Settings โ†’ Tags, then assigned to individual series or movies from their edit page.

Tag Behaviour
provider-animeunity Uses AnimeUnity for that title
provider-<site> Uses any supported VibraVid site for that title
hold / pausa Skips the item until the tag is removed
skip-s1, skip-s2, โ€ฆ Skips a specific season of a series

Method 2 โ€” Global fallback list (recommended, zero per-title configuration)

Configure provider_fallback with an ordered list of providers. VibraVid tries them in sequence and stops at the first that finds a matching title. No tagging required โ€” add as many providers as you want as safety nets.

Recommended full configuration (covers general content, anime, and niche services):

"provider_fallback": [
    "streamingcommunity",
    "animeunity",
    "discoveryplus",
    "discovery",
    "dmax",
    "nove",
    "realtime",
    "mediasetinfinity",
    "raiplay",
    "homegardentv",
    "foodnetwork",
    "animeworld",
    "crunchyroll",
    "primevideo",
    "tubitv",
    "cinezo",
    "mostraguarda"
]

If provider_fallback is empty or omitted, VibraVid tries streamingcommunity only and fails if the title is not found there.

Italian dub preference (download_italian_anime_default)

When true, if the selected provider returns both an original-language version and an (ITA) dubbed version of the same title, VibraVid automatically picks the Italian dub. This applies regardless of which method selected the provider.

"download_italian_anime_default": true

Path mapping โ€” essential for split environments

path_mapping is one of the most important settings when Radarr/Sonarr run in Docker while VibraVid runs on the host (or vice versa). After a download completes, VibraVid must tell Radarr/Sonarr exactly where the file is so they can import it. If the two services see the same physical folder under different paths, Radarr/Sonarr will receive a path they cannot resolve and the import will fail.

Setup path_mapping needed?
Both on bare metal No
Both in Docker with identical volume mounts No
VibraVid on host, ARR stack in Docker Yes
Both in Docker with different volume mounts Yes

Example: VibraVid on the host sees /media/Media/Film. Radarr's Docker Compose mounts the same folder at a different path:

volumes:
  - /media/Media/Film:/media/Film
  - /media/Media/Anime:/media/Anime
  - /media/Media/Series:/media/Series

Without path_mapping, VibraVid reports /media/Media/Film/my-movie to Radarr. Radarr looks for that path inside its container โ€” it does not exist there โ€” and the import fails. With the mapping configured, VibraVid automatically translates the path before every API call:

"path_mapping": {
    "/media/Media/Film":   "/media/Film",
    "/media/Media/Anime":  "/media/Anime",
    "/media/Media/Series": "/media/Series"
}

Each key is a prefix as seen by VibraVid; the value is the equivalent prefix inside the Radarr/Sonarr container. Entries are checked in order and the first matching prefix is replaced. Leave path_mapping as {} when both services share the same filesystem view.


DRM

{
  "DRM": {
    "use_cdm": true,
    "prefer_remote_cdm": true,
    "vault": {
      "supa": {
        "url": "https://crqczuxpqjmrjvdvqvlx.supabase.co",
        "token": ""
      }
    }
  }
}
Key Default Description
use_cdm true Enable CDM-based key extraction. When false, only database lookups are attempted
prefer_remote_cdm true Prefer remote CDM services over local device files
vault โ€” Optional external DRM key store, queried before CDM extraction

Remote CDM Services

When remote CDM services are available, add one or both of the following blocks to config.json:

Widevine:

"widevine": {
  "device_type": "ANDROID",
  "system_id": 22590,
  "security_level": 3,
  "host": "https://cdrm-project.com/remotecdm/widevine",
  "secret": "CDRM",
  "device_name": "public"
}
Key Description
device_type Device model: "ANDROID" or "CHROME"
system_id Widevine system ID (default 22590 for Android)
security_level Security level 1โ€“3 (3 = L3)
host Remote CDM server URL
secret Authentication secret
device_name Device identifier registered on the remote service

PlayReady:

"playready": {
  "device_name": "public",
  "security_level": 3000,
  "host": "https://cdrm-project.com/remotecdm/playready",
  "secret": "CDRM"
}
Key Description
device_name Device identifier registered on the remote service
security_level Security level (e.g. 3000 for SL3000)
host Remote CDM server URL
secret Authentication secret

Local CDM Devices

To use local CDM device files instead of remote services, place them in the project root:

  • Widevine: .wvd file (from pywidevine)
  • PlayReady: .prd file (from pyplayready)

Set prefer_remote_cdm to false and local devices will be picked up automatically.


Usage Examples

Basic Commands

# Show help and available sites
python manual.py -h

# Search and download
python manual.py --site streamingcommunity --search "interstellar"

# Auto-download the first result
python manual.py --site streamingcommunity --search "interstellar" --auto-first

# Use a site by its index number
python manual.py --site 0 --search "interstellar"

Series Selection

Use --season and --episode to skip interactive prompts:

# Specific episode
python manual.py --site streamingcommunity --search "breaking bad" --auto-first --season 1 --episode 3

# Range of episodes
python manual.py --site streamingcommunity --search "breaking bad" --auto-first --season 1 --episode "1-5"

# All episodes of a season
python manual.py --site streamingcommunity --search "breaking bad" --auto-first --season 1 --episode "*"

# All episodes of all seasons
python manual.py --site streamingcommunity --search "breaking bad" --auto-first --season "*"

# Multiple seasons
python manual.py --site streamingcommunity --search "breaking bad" --auto-first --season "1-3"

Year Filter

# Exact year
python manual.py --site streamingcommunity --search "dune" --year 2021

# Year range
python manual.py --site streamingcommunity --search "batman" --year "1990-2015"

Stream Track Overrides

# Video resolution
python manual.py --site streamingcommunity --search "interstellar" -sv 1080

# Audio language
python manual.py --site streamingcommunity --search "interstellar" -sa "eng"

# Subtitles
python manual.py --site streamingcommunity --search "interstellar" -ss "eng"

Console Behaviour Override

# Keep console open (loop mode)
python manual.py --close-console false

# Close console after download
python manual.py --site streamingcommunity --search "interstellar" --close-console true

Proxy

python manual.py --site streamingcommunity --search "interstellar" --use_proxy

Show Dependency Paths

python manual.py --dep

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

Advanced Features

Hook System

Execute custom scripts at specific points in the download lifecycle. Hooks are configured in config.json under the HOOKS key.

Available stages:

  • pre_run โ€” runs before the main flow starts
  • post_download โ€” runs after each individual download completes (in the GUI, once per item)
  • post_run โ€” runs once when the overall execution ends
{
  "HOOKS": {
    "pre_run": [
      {
        "name": "prepare-env",
        "type": "python",
        "path": "scripts/prepare.py",
        "args": ["--clean"],
        "env": { "MY_FLAG": "1" },
        "cwd": "~",
        "os": ["linux", "darwin"],
        "timeout": 60,
        "enabled": true,
        "continue_on_error": true
      }
    ],
    "post_download": [
      {
        "name": "post-download-env",
        "type": "python",
        "path": "/app/script.py",
        "args": ["{download_path}"],
        "env": { "MY_FLAG": "1" },
        "cwd": "~",
        "os": ["linux"],
        "timeout": 60,
        "enabled": true,
        "continue_on_error": true
      }
    ],
    "post_run": [
      {
        "name": "notify",
        "type": "bash",
        "command": "echo 'Download completed'"
      }
    ]
  }
}

Hook Options

Key Description
name Descriptive label for the hook
type Script type: python, bash, sh, shell, bat, cmd
path Path to script file (alternative to command)
command Inline command to execute (alternative to path). Note: args are ignored when using command
args List of arguments passed to the script
env Additional environment variables as key-value pairs
cwd Working directory for execution (supports ~ and env vars)
os Optional OS filter: ["windows"], ["darwin"], ["linux"], or any combination
timeout Maximum execution time in seconds (hook fails if exceeded)
enabled Enable or disable the hook without removing it
continue_on_error If false, stops execution when the hook fails

Hook Types

  • Python: runs with the current Python interpreter
  • Bash / sh / shell: executed via /bin/bash -c on macOS/Linux
  • Bat / cmd / shell: executed via cmd /c on Windows
  • Inline commands: use command instead of path for simple one-liners

Context Placeholders

Placeholder Description
{download_path} Absolute path of the downloaded file
{download_dir} Directory containing the downloaded file
{download_filename} Filename of the downloaded file
{download_id} Internal download identifier
{download_title} Download title
{download_site} Source site name
{download_media_type} Media type
{download_status} Final download status
{download_error} Error message, if any
{download_success} 1 on success, 0 on failure
{stage} Current hook stage

The same values are also exposed as environment variables with the SC_ prefix (e.g. SC_DOWNLOAD_PATH, SC_DOWNLOAD_SUCCESS, SC_HOOK_STAGE).


ARR Integration

VibraVid can be used as an automation component in a media-server stack with Seerr/Jellyseerr, Sonarr, and Radarr.

Typical flow:

Seerr / Jellyseerr
    โ†“ user requests a movie or series
Sonarr / Radarr
    โ†“ media is added and marked as missing
VibraVid ARR
    โ†“ detects missing media through polling or webhooks
VibraVid downloader
    โ†“ searches and downloads through the configured provider or through the provider selected by tag
Sonarr / Radarr
    โ†“ rescans/imports the downloaded file
Media library
    โ†“ Jellyfin/Plex can detect the final file

Supported integrations

Service Role
Seerr/Jellyseerr Handles user requests and sends approval/pending webhook events
Sonarr Manages TV series, missing episodes, episode metadata, rescans and imports
Radarr Manages movies, missing movie metadata, rescans and imports
VibraVid Searches, downloads and hands files back to Sonarr/Radarr

Webhook endpoints

When the GUI/Django server is running, the ARR integration exposes dedicated webhook endpoints:

POST /api/arr/webhook/seerr/
POST /api/arr/webhook/sonarr/
POST /api/arr/webhook/radarr/

Each endpoint can be protected with its own webhook secret. Configure the same secret both in VibraVid and in the corresponding external service.

Manual and automatic sync

ARR can process media in two ways:

  1. Polling โ€” VibraVid periodically asks Sonarr/Radarr for wanted or missing media.
  2. Webhooks โ€” VibraVid reacts immediately when Seerr, Sonarr or Radarr sends an event.

Both modes can be enabled together. Native Sonarr/Radarr webhooks can be prioritized over Seerr events to reduce duplicate processing.

Sonarr workflow

For series, VibraVid ARR can:

  • read missing episodes from Sonarr;
  • resolve series, season and episode metadata;
  • download the requested episode into the expected series path;
  • trigger a Sonarr rescan/import;
  • verify whether the episode was imported;
  • optionally mark the episode as unmonitored after successful import.

Radarr workflow

For movies, VibraVid ARR can:

  • read missing movies from Radarr;
  • resolve title, year and TMDB metadata;
  • download the requested movie into the expected movie path;
  • trigger a Radarr rescan/import;
  • verify whether the movie was imported;
  • optionally mark the movie as unmonitored after successful import.

Recommended setup

Use shared volumes so VibraVid and Sonarr/Radarr see the same filesystem paths. If containers use different internal paths for the same media folder, imports may fail because Sonarr/Radarr will not find the downloaded files.

Example Docker path layout:

/media
โ”œโ”€โ”€ movies
โ”œโ”€โ”€ series
โ””โ”€โ”€ downloads

Mount the same media root into VibraVid, Sonarr and Radarr whenever possible.


Docker

Recommended: Docker Compose

docker-compose up -d        # Start
docker-compose logs -f      # View logs
docker-compose down         # Stop (data persists)

For NAS users (Synology, TrueNAS, Unraid, etc.), see docs/NAS.md for a step-by-step setup guide including bind mounts and permission configuration.

Custom paths and ports

Copy the provided template and edit the values you need:

cp .env.example .env

Key variables (full list in .env.example):

Variable Default Description
VIBRAVID_PORT 8000 Host port exposed by the container
VIBRAVID_VIDEO_DIR named volume Where downloads land on the host (e.g. /volume2/Movies)
VIBRAVID_DB_DIR named volume Host path for the SQLite database
VIBRAVID_CONFIG_DIR named volume Host path for config.json / login.json
VIBRAVID_LOGS_DIR named volume Host path for application logs
ALLOWED_HOSTS localhost,127.0.0.1 Comma-separated hostnames Django accepts
CSRF_TRUSTED_ORIGINS http://localhost:8000,... Origins for CSRF validation

NAS example โ€” store downloads on a NAS share, expose on port 9000:

VIBRAVID_PORT=9000
VIBRAVID_VIDEO_DIR=/volume2/Movies
VIBRAVID_DB_DIR=/volume1/docker/vibravid/db
VIBRAVID_CONFIG_DIR=/volume1/docker/vibravid/conf
VIBRAVID_LOGS_DIR=/volume1/docker/vibravid/logs
ALLOWED_HOSTS=localhost,127.0.0.1,192.168.1.100
CSRF_TRUSTED_ORIGINS=http://192.168.1.100:9000

Then start normally:

docker-compose up -d

Private Network Deployment

Uncomment and edit the environment section in docker-compose.yml:

environment:
  DJANGO_DEBUG: "false"
  ALLOWED_HOSTS: "streaming.example.local,localhost,127.0.0.1,192.168.1.50"
  CSRF_TRUSTED_ORIGINS: "https://streaming.example.local"
  USE_X_FORWARDED_HOST: "true"
  SECURE_PROXY_SSL_HEADER_ENABLED: "true"
  CSRF_COOKIE_SECURE: "true"
  SESSION_COOKIE_SECURE: "true"
  DJANGO_SECRET_KEY: "your-secure-secret-key-here"

ARR-related variables can be added to the same environment block:

environment:
  USE_ARR_SERVICES: "true"
  SONARR_URL: "http://sonarr:8989"
  SONARR_API_KEY: "your-sonarr-api-key"
  RADARR_URL: "http://radarr:7878"
  RADARR_API_KEY: "your-radarr-api-key"
  SEERR_WEBHOOK_SECRET: "your-seerr-secret"
  SONARR_WEBHOOK_SECRET: "your-sonarr-secret"
  RADARR_WEBHOOK_SECRET: "your-radarr-secret"

Manual Docker Build

docker build -t vibravid .

docker run -d \
  --name vibravid \
  -p 8000:8000 \
  -v vibravid_db:/app/data \
  -v vibravid_videos:/app/Video \
  -v vibravid_logs:/app/logs \
  -v vibravid_config:/app/Conf \
  --restart unless-stopped \
  vibravid

Binding Local Folders

# Linux/macOS
docker run -d --name vibravid -p 8000:8000 \
  -v ~/Downloads/Videos:/app/Video \
  vibravid

# Windows (PowerShell)
docker run -d --name vibravid -p 8000:8000 `
  -v "D:\Video:/app/Video" `
  vibravid

Updating (Docker)

When a new version is released, VibraVid shows an update banner in the web UI. Click Update now to trigger the update.

The container cannot restart itself โ€” it writes a marker file to /app/data/.update_requested. A host-side script (docker/scripts/nas-update.sh) picks it up and runs:

docker compose pull
docker compose up -d

To use the one-click update, install and start docker/scripts/nas-update.sh on the host. See scripts/README.md for setup instructions (systemd, Synology Scheduled Task, cron).

Manual update (works without the script):

docker compose pull
docker compose up -d

Known Issues

The following issues are known and are expected to be addressed in upcoming releases. They do not affect the core download functionality but may impact the user experience in specific scenarios.

Download progress not shown for some providers

For certain providers the download progress bar in the GUI may not update or may remain at 0% for the duration of the download. The download is still running in the background and will complete normally โ€” the issue is limited to the progress display. This typically affects providers that stream through intermediate layers rather than exposing direct segment URLs.

Velora Bridge console errors (connection / rate limit)

During downloads that go through Velora Bridge you may see warnings or errors in the console such as connection timeouts, stream read failures, or retry messages. These are caused by transient network conditions, proxy rate limiting, or per-session connection limits on the provider side. Velora Bridge retries automatically and the download usually completes successfully. If errors persist, check your proxy configuration and ensure the provider is not applying a rate limit to your IP.


Related Projects

  • MammaMia โ€” Stremio addon for Italian streaming (by UrloMythus)
  • Unit3Dup โ€” Torrent automation for Unit3D tracker (by 31December99)
  • N_m3u8DL-RE โ€” Universal downloader for HLS/DASH/ISM (by nilaoda)
  • pywidevine โ€” Widevine L3 decryption library (by devine-dl)
  • pyplayready โ€” PlayReady decryption library (by ready-dl)

Disclaimer

This software is for educational and research purposes only. The authors:

  • DO NOT assume responsibility for illegal use
  • DO NOT provide or facilitate DRM circumvention tools, CDMs, or decryption keys
  • DO NOT endorse piracy or copyright infringement

By using this software, you agree to comply with all applicable laws and confirm you have rights to any content you process. No warranty is provided.


Made with โค๏ธ for streaming lovers

If you find this project useful, consider starring it! โญ

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

vibravid-1.2.5.tar.gz (320.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

vibravid-1.2.5-py3-none-any.whl (380.2 kB view details)

Uploaded Python 3

File details

Details for the file vibravid-1.2.5.tar.gz.

File metadata

  • Download URL: vibravid-1.2.5.tar.gz
  • Upload date:
  • Size: 320.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for vibravid-1.2.5.tar.gz
Algorithm Hash digest
SHA256 32630880f23f6cee83d602bdf9fd6a561db7d1ecfb07a5105552cc3b1232f0c3
MD5 1de7515753a986305b14a602404969ed
BLAKE2b-256 3e0f2cf2a38bccd66a2a4fb612809bf0c7b2405fcdff0965dda7de220678993f

See more details on using hashes here.

File details

Details for the file vibravid-1.2.5-py3-none-any.whl.

File metadata

  • Download URL: vibravid-1.2.5-py3-none-any.whl
  • Upload date:
  • Size: 380.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for vibravid-1.2.5-py3-none-any.whl
Algorithm Hash digest
SHA256 29794d70108e7ce9b5f2e3f7e121790128d2103182f55c2d54a662322b0687c7
MD5 abd7a5aded9809d3ae0ccee84e6e7b0e
BLAKE2b-256 86dda1a1095078761747121e9fde3ae59993d1c95ed125b7b85affdd93e353eb

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page