A high-performance Jellyfin cast receiver that controls an external MPV player.
Built with Tauri v2, Solid.js, and Rust.
Features β’ Roadmap β’ Quick Start β’ Architecture β’ Troubleshooting
JMSR allows you to cast media from any Jellyfin client (web, mobile, TV) to your desktop, where it plays in MPV with full support for your custom configurations, shaders, and scripts.
π‘ Key Philosophy
JMSR does NOT embed
libmpv. Instead, it spawns and controls a standalone MPV process via JSON IPC. This preserves your existingmpv.conf, shader packs (Anime4K, FSR, etc.), and all local customizations without compromise.
| Feature | Description |
|---|---|
| πΊ Cast Target | Appears as a controllable device in Jellyfin's cast menu |
| π External MPV | Full compatibility with your system MPV configuration and shaders |
| π Persistent Auth | Login once, stay connected with secure token storage |
| π Auto-Reconnect | Resilient WebSocket connection with exponential backoff strategy |
| βοΈ Smart Playback | Automatically plays the next episode when the current one finishes |
| π§ Series Memory | Remembers audio/subtitle language preferences per TV series |
| β¨οΈ Shortcuts | Use Shift+N / Shift+P directly in MPV to skip episodes |
| π₯οΈ System Tray | Runs quietly in the background with quick access controls |
| π‘οΈ Type-Safe | 100% type-safe Rust-to-TypeScript communication via tauri-specta |
| π Cross-Platform | Native support for Windows, macOS, and Linux |
- Quick Connect - Login via code from another device
- Intro Skipper Integration - Auto-skip intros/credits
- Full-Featured Client UI - Browse libraries, manage media, and control playback like other Jellyfin clients
- Embedded Player - Optional built-in video player without external MPV dependency
- MPRIS Support - Linux media player integration for desktop controls
- Discord Rich Presence - Show current playback status on Discord profile
- Custom Shaders Manager - Easy toggle for Anime4K, FSR, and other MPV shaders
- SyncPlay Support - Watch together with friends via Jellyfin SyncPlay group
- Picture-in-Picture (PiP) - Floating mini-player mode
- Global Hotkeys - Customizable shortcuts that work in the background
- Offline Mode - Download media for offline playback
JMSR utilizes a robust three-actor architecture to ensure stability and separation of concerns.
graph LR
subgraph JMSR[JMSR Desktop App]
A[<b>Sentinel</b><br>Tauri GUI]
B[<b>Bridge</b><br>Rust Backend]
A <--> B
end
B <-->|JSON IPC| C[<b>Player</b><br>External MPV]
B <-->|WebSocket + REST| D[<b>Jellyfin Server</b>]
style A fill:#00a4dc,stroke:#333,color:white
style B fill:#dea584,stroke:#333,color:black
style C fill:#4c3c69,stroke:#333,color:white
style D fill:#aa5cc3,stroke:#333,color:white
- Sentinel (Tauri GUI): Handles UI, WebSocket connection to Jellyfin, and state management.
- Bridge (Rust IPC): Translates commands and manages the external process.
- Player (MPV): The standalone media player instance running your config.
- MPV installed and in PATH
Download the latest release for your platform from the Releases page:
| Platform | Download |
|---|---|
| Windows | .msi (installer) or .exe (NSIS) |
| macOS | .dmg |
| Linux | .deb or .AppImage |
Development prerequisites
# Clone the repository
git clone https://github.com/your-username/jmsr.git
cd jmsr
# Install dependencies
bun install
# Build production binaries
bunx tauri buildBinaries will be in src-tauri/target/release/bundle/.
- Launch JMSR from your application menu or terminal.
- Authenticate by entering your Jellyfin server URL and credentials.
- Cast Media: JMSR will appear as "JMSR" in your Jellyfin client's cast menu.
- Enjoy: Media plays in MPV on your desktop with full control syncing.
- Authentication: User logs into Jellyfin and receives an access token.
- Registration: JMSR posts capabilities to
/Sessions/Capabilities/Full. - WebSocket: Connects to Jellyfin for real-time play state control.
- Cast Event: When user casts, Jellyfin sends a
Playcommand. - MPV Control: JMSR spawns MPV (if needed) and sends JSON IPC commands.
- Progress: Event-driven progress reporting via MPV property observation.
- Sync: Pause/seek/volume commands flow bidirectionally (Jellyfin β MPV).
- Auto-Play: Automatically fetches the next episode upon natural file end.
jmsr/
βββ src/ # Solid.js frontend
β βββ index.tsx # Entry point
β βββ bindings.ts # Auto-generated IPC bindings
β βββ components/ # UI components
βββ src-tauri/ # Rust backend
β βββ src/
β β βββ jellyfin/ # Jellyfin client implementation
β β βββ mpv/ # MPV IPC driver logic
β βββ tauri.conf.json # Tauri configuration
βββ doc/PRD.md # Product requirements| Task | Command |
|---|---|
| Frontend Dev | bun run dev |
| Tauri Dev | bunx tauri dev |
| Build Prod | bunx tauri build |
| Test | bun run test |
| Lint/Format | bun run check |
- TypeScript: Single quotes, Biome formatting.
- Rust: 2-space indent (standard
rustfmt.toml). - IPC: Always use typed
commands.*from bindings, never rawinvoke(). - Solid.js: Use
createSignal,createResourceβ NOT React hooks.
- Add function in
src-tauri/src/command.rswith#[tauri::command]and#[specta]. - Register in
src-tauri/src/lib.rsinsidecollect_commands![]. - Regenerate bindings by running
bunx tauri dev. - Import from
commandsin your TypeScript file.
| Component | Technology |
|---|---|
| Framework | Tauri v2 |
| Frontend | Solid.js + TypeScript |
| Backend | Rust |
| Bundler | Rsbuild |
| Styling | TailwindCSS |
| IPC | tauri-specta |
| Linting | Biome |
| Testing | Rstest |
JMSR doesn't appear as cast target
- Ensure you're logged in (check Settings page shows "Connected").
- Refresh the Jellyfin web page after JMSR connects.
- Check Jellyfin Dashboard > Activity for the JMSR session.
MPV doesn't start
- Verify MPV is installed:
mpv --version. - Check MPV is in PATH (or set explicit path in Settings).
- Windows (Scoop): JMSR auto-resolves symlinks, but ensure the shim is valid.
- Check Settings > MPV Player for detected path.
Video doesn't play
- Check Jellyfin transcoding settings.
- Verify network connectivity to Jellyfin server.
- Check JMSR log panel (Settings page) for error messages.
Connection lost
- JMSR auto-reconnects with exponential backoff (1s β 60s).
- Check network connectivity.
- Toast notifications will indicate connection status.
Contributions are welcome! Please follow these steps:
- Fork the repository.
- Create a feature branch.
- Follow existing code conventions (Biome for TS, rustfmt for Rust).
- Run
bun run checkbefore committing. - Submit a pull request.
MIT License - see LICENSE for details.
- jellyfin-mpv-shim - The original Python inspiration.
- Tauri - For the amazing desktop framework.
- MPV - The best media player in existence.