A Rust-based service that maps your Real-Debrid torrent library to a Jellyfin/Plex-compatible WebDAV endpoint with automatic media identification via TMDB.
I created this project as:
- I was using the various arrs, and found it cumbersome, plus I ran out of storage space, meaning I needed to use a Debrid service of some kind
- Zurg didn't work for me as I needed the folder structure for Jellyfin
I use Debrid Media Manager for keeping Real Debrid populated at the moment, but am thinking of incorporating that into this service as well.
Note that this is still a work in progress and is provided as-is for educational purposes only.
Future work:
- Test with Kodi
- Add a web-ui to track progress and correct mismatches
- Automatically populate Read Debrid with watchlist content from Trakt and newly released episodes from already tracked shows
This was 100% vibe coded using a mix of Claude and Junie as further AI experimentation.
- Media Identification: Automatically identifies movies and TV shows using TMDB metadata based on torrent filenames.
- Jellyfin/Plex Structure: Organizes your library into a clean
Movies/andShows/directory structure. - Season Grouping: Automatically groups TV show episodes into
Season XXfolders. - WebDAV Endpoint: Exposes a WebDAV server (port 8080) serving
.strmfiles that point to Real-Debrid download URLs. Mount via rclone for use with Jellyfin/Plex. - On-Demand Repair: Detects broken links at playback time (503 from Real-Debrid) and automatically re-downloads the torrent via its magnet link without user intervention.
- Persistent Cache: Uses an embedded database (
redb) to cache media identifications, reducing API calls and speeding up restarts. - Configurable Scan Interval: Customizable scan interval via environment variable.
- Robust Identification Logic: Handles complex torrent naming conventions, including CamelCase splitting, technical metadata stripping, and multi-service fallback strategies.
- Jellyfin Notifications: Optionally notifies Jellyfin when content changes so new episodes and movies appear immediately without waiting for a full library scan.
- A Real-Debrid account and API Token.
- A TMDB API Key (The Movie Database).
The service is configured via environment variables. You can use a .env file in the project root:
RD_API_TOKEN=your_real_debrid_token
TMDB_API_KEY=your_tmdb_api_key
# Optional
SCAN_INTERVAL_SECS=60 # How often to scan for new torrents (default: 60)
# Optional: Jellyfin integration (all three required to enable)
JELLYFIN_URL=http://jellyfin:8096
JELLYFIN_API_KEY=your_jellyfin_api_key
JELLYFIN_RCLONE_MOUNT_PATH=/media| Variable | Required | Default | Description |
|---|---|---|---|
RD_API_TOKEN |
Yes | - | Your Real-Debrid API token |
TMDB_API_KEY |
Yes | - | Your TMDB (The Movie Database) API key |
SCAN_INTERVAL_SECS |
No | 60 | Interval between torrent library scans (runs immediately on startup) |
JELLYFIN_URL |
No | - | Jellyfin server URL for library update notifications |
JELLYFIN_API_KEY |
No | - | Jellyfin API key for authentication |
JELLYFIN_RCLONE_MOUNT_PATH |
No | - | rclone mount path as seen by Jellyfin (e.g. /media) |
The easiest way to run DebridMovieMapper is using Docker. Pre-built multi-platform images are available via the GitHub Container Registry.
docker pull ghcr.io/phrontizo/debridmoviemapper:latestdocker run -d \
--name debridmoviemapper \
-p 8080:8080 \
-e RD_API_TOKEN=your_token \
-e TMDB_API_KEY=your_api_key \
-e SCAN_INTERVAL_SECS=60 \
-v $(pwd)/metadata.db:/metadata.db \
ghcr.io/phrontizo/debridmoviemapper:latestIf you prefer to build the image yourself, you can use the provided build.sh script for multi-platform builds:
./build.shOr build locally for your current architecture:
docker build -t debridmoviemapper .Note: Mounting metadata.db ensures your media identification cache is preserved across container recreations.
Upgrading from sled (pre-redb): If you previously ran an older version that used sled, your metadata.db will be a directory. Remove it before starting the new version: rm -rf metadata.db. The redb database will be recreated automatically (TMDB identifications will be re-fetched on the first scan).
The recommended way to use DebridMovieMapper with Jellyfin is via Docker Compose with rclone mounting the WebDAV endpoint.
A complete compose.yml file is provided in the repository that includes:
- DebridMovieMapper service
- rclone for mounting the WebDAV endpoint
- Jellyfin for media playback
Create an rclone.conf file in the same directory with the following content:
[debrid]
type = webdav
url = http://debridmoviemapper:8080
vendor = other-
Create required files and directories:
touch metadata.db rclone.conf mkdir -p rclone && chown 65534:65534 rclone -
Add your Real-Debrid and TMDB credentials to the
compose.ymlfile -
Add the rclone configuration to
rclone.conf(see above) -
Start the services:
docker compose up -d
-
Access Jellyfin at
http://localhost:8096and add/mediaas a library path -
(Optional) To enable instant library updates, set
JELLYFIN_API_KEYincompose.ymlto your Jellyfin API key
- The WebDAV server runs on port 8080 internally (mapped to 8082 on the host)
- rclone mounts the WebDAV endpoint to
./rcloneon the host via a bind mount - Jellyfin reads from
/mediawhich is bind-mounted from./rclone - Files appear as
.strmfiles containing Real-Debrid download URLs - Jellyfin will stream directly from Real-Debrid when playing content
Once running, the WebDAV server will be available at http://localhost:8080. Mount it with rclone and point your media server at the mount:
- Jellyfin (via rclone mount - see Docker Compose example above)
- Plex (via rclone mount)
- Kodi
- Infuse (iOS/tvOS/macOS)
- Language: Rust 2024
- Libraries:
dav-server: WebDAV protocol implementation.tokio: Async runtime.reqwest: HTTP client withrustls.redb: Embedded ACID key-value store.serde: Serialization/Deserialization.regex: Filename parsing and cleaning.
src/main.rs: Entry point — initialises shared state and starts the WebDAV server.src/tasks.rs: Background scan loop — polls Real-Debrid, identifies new torrents, updates the VFS.src/rd_client.rs: Real-Debrid API client with adaptive token bucket rate limiter and response caching.src/tmdb_client.rs: TMDB API client for media metadata.src/repair.rs: On-demand torrent repair state machine triggered at playback time.src/vfs.rs: Virtual File System logic for library organisation.src/dav_fs.rs: WebDAV filesystem — re-unrestricts links on read and triggers repair on 503.src/identification.rs: Smart media identification and filename cleaning logic.src/error.rs: Unified error type (AppError) usingthiserror.src/jellyfin_client.rs: Optional Jellyfin notification client for instant library updates.src/mapper.rs: Library root (module declarations).
The service runs one background task:
- Scan Task: Polls Real-Debrid for new/updated torrents and updates the virtual filesystem
- Runs immediately on startup
- Repeats every
SCAN_INTERVAL_SECS(default: 60 seconds) - Files that fail to unrestrict at scan time are silently skipped
There is no background repair loop. Instead, repair is triggered at playback time:
- When a
.strmfile is read,dav_fsre-callsunrestrict_linkfor a fresh URL (the 1-hour response cache makes this free when the torrent is healthy) - If
unrestrict_linkreturns a 503, the torrent is marked broken and a backgroundtokio::spawncallsrepair_by_id - Broken/repairing torrents are hidden from WebDAV until healthy again
When JELLYFIN_URL, JELLYFIN_API_KEY, and JELLYFIN_RCLONE_MOUNT_PATH are all set, the service notifies Jellyfin of specific changed paths after each VFS update. This uses Jellyfin's POST /Library/Media/Updated API to trigger targeted scans of only the affected folders (e.g. a single season directory for a new episode), avoiding full library rescans. Changes from all sources — new torrents, deletions, repairs — are detected automatically.
Some torrents contain RAR/ZIP archives instead of video files. Real-Debrid does not extract these archives, so they cannot be streamed. When such a torrent is detected, a warning is logged:
WARN Torrent 'Movie.Name.1080p.BluRay' contains only archive files (RAR/ZIP) and cannot be streamed — replace with a non-archive version on Real-Debrid
To fix this, delete the torrent from Real-Debrid and find an alternative release that contains video files directly (.mkv, .mp4, etc.).
- 503 Service Unavailable: Immediately marks torrent as broken and triggers repair without retries
- 429 Rate Limit: Adaptive token bucket rate limiter shared across all API calls — on 429, the global request interval doubles (max 2s between requests) and Retry-After headers are respected; on success, the interval gradually recovers toward the baseline of 10 req/s
- 404 Not Found: Treated as success for delete operations (idempotent)
- Playback Errors: WebDAV read failures automatically trigger repair process
- Unrestrict responses: Cached for 1 hour to reduce API load
- TMDB metadata: Persisted to embedded database (
metadata.db) indefinitely
MIT