jmsr hewel
winget install --id=pigfun.jmsr -e A high-performance Jellyfin cast receiver that controls an external MPV player.
winget install --id=pigfun.jmsr -e A high-performance Jellyfin cast receiver that controls an external MPV player.
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 existing mpv.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 |
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>Tauri GUI]
B[<b>Bridge</b>Rust Backend]
A <--> B
end
B <-->|JSON IPC| C[<b>Player</b>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
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 build
Binaries will be in src-tauri/target/release/bundle/.
/Sessions/Capabilities/Full.Play command.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 |
rustfmt.toml).commands.* from bindings, never raw invoke().createSignal, createResource — NOT React hooks.src-tauri/src/command.rs with #[tauri::command] and #[specta].src-tauri/src/lib.rs inside collect_commands![].bunx tauri dev.commands in 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
MPV doesn't start
mpv --version.Video doesn't play
Connection lost
Contributions are welcome! Please follow these steps:
bun run check before committing.MIT License - see LICENSE for details.