A high-performance Jellyfin and Emby desktop client that controls an external MPV player.
Built with Tauri v2, Solid.js, and Rust.
Features β’ Roadmap β’ Quick Start β’ Architecture β’ Troubleshooting
JellyPilot lets you sign in to Jellyfin or Emby, browse your video libraries, and play media in MPV with full support for your custom configurations, shaders, and scripts. For Jellyfin, JellyPilot can also register as a cast target for playback from other Jellyfin clients.
π‘ Key Philosophy
JellyPilot 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 |
|---|---|
| ποΈ Jellyfin + Emby | Connect to Jellyfin or Emby servers with saved service profiles |
| π Library Browser | Browse Movies and Shows, open item details, and start playback from the desktop app |
| πΊ Jellyfin Cast Target | Appears as a controllable device in Jellyfin's cast menu |
| π External MPV | Full compatibility with your system MPV configuration and shaders |
| π‘οΈ Type-Safe | 100% type-safe Rust-to-TypeScript communication via tauri-specta |
| π Persistent Auth | Login once, stay connected with secure token storage |
| π Jellyfin Quick Connect | Authenticate with Jellyfin by approving a one-time code on another device |
| π Auto-Reconnect | Resilient WebSocket connection with exponential backoff strategy |
| βοΈ Smart Playback | Automatically plays the next episode when the current one finishes |
| βοΈ Jellyfin Intro Skipper | Automatically skips Intro Skipper plugin introduction and credit ranges |
| π§ Series Memory | Remembers audio/subtitle language preferences per TV series |
| β¨οΈ Shortcuts | Use configurable MPV shortcuts (Shift+> / Shift+< by default) to skip episodes |
| π₯οΈ System Tray | Runs quietly in the background with quick access controls |
| π Cross-Platform | Native support for Windows, macOS, and Linux |
| Server | Supported | Notes |
|---|---|---|
| Jellyfin | β | Password login, Quick Connect, saved profiles, library browsing, MPV playback, cast target registration, remote control, and Intro Skipper plugin support |
| Emby | β | Password login, saved profiles, library browsing, MPV playback, remote control, and playback progress reporting |
Emby support uses the same library and player workflow as Jellyfin where the server APIs are compatible. Jellyfin-specific features such as Quick Connect and the Jellyfin Intro Skipper plugin are not advertised for Emby connections.
- 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 media server clients
- Embedded Player - Optional built-in video player without external MPV dependency
- MPRIS Support - Linux media player integration for desktop controls
- Added saved-session route gating and automatic reconnect through the authenticated session access path.
- Added mute-state visibility to the Now Playing controls.
- Improved Player Bridge command handling, playback control sharing, and Jellyfin websocket ownership for more reliable external MPV control.
- Migrated login, diagnostics, settings, subtitle priorities, session dialog, and now playing controls to headless Ark UI Solid primitives while preserving JellyPilot Control Room styling and behavior.
- Added Arch Linux
.pkg.tar.zstrelease packaging.
- Added Intro Skipper plugin support for automatic introduction and credit skips.
- Added a global Automation toggle to enable or disable Intro Skipper behavior.
- Added once-per-session skip semantics so manual seeks back into skipped ranges are respected.
- Added verification coverage for plugin failures, malformed ranges, disabled behavior, progress reporting, and existing track controls.
JellyPilot utilizes a robust three-actor architecture to ensure stability and separation of concerns.
graph LR
subgraph JellyPilot[JellyPilot 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 / Emby 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, server connection, 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, .AppImage, or Arch Linux .pkg.tar.zst |
Install the Arch Linux package from a release asset with:
sudo pacman -U jellypilot-<version>-1-x86_64.pkg.tar.zstDevelopment prerequisites
# Clone the repository
git clone https://github.com/hewel/jellypilot.git
cd jellypilot
# Install dependencies
bun install
# Build production binaries
bunx tauri buildBinaries will be in src-tauri/target/release/bundle/.
- Launch JellyPilot from your application menu or terminal.
- Choose a server type: Select Jellyfin or Emby on the login screen.
- Authenticate with your server URL and credentials. Jellyfin also supports Quick Connect.
- Browse or Cast Media: Start playback from JellyPilot's Library view. Jellyfin users can also cast to "JellyPilot" from another Jellyfin client.
- Optional Jellyfin Intro Skipper: Install the Jellyfin Intro Skipper plugin and keep Operations Console > Automation > Automatic Intro Skip enabled to skip detected intros and credits.
- Enjoy: Media plays in MPV on your desktop with full control syncing.
- Authentication: User logs into Jellyfin or Emby and receives an access token.
- Registration: JellyPilot posts supported capabilities to the active media server.
- WebSocket: Connects to the server for real-time play state control when supported.
- Play Event: Playback can start from JellyPilot's Library Browser or from Jellyfin cast commands.
- MPV Control: JellyPilot 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 between the server and MPV where supported.
- Auto-Play: Automatically fetches the next episode upon natural file end.
jellypilot/
βββ src/ # Solid.js frontend
β βββ index.tsx # Entry point
β βββ bindings.ts # Auto-generated IPC bindings
β βββ components/ # UI components
βββ src-tauri/ # Rust backend
β βββ src/
β β βββ jellyfin/ # Jellyfin/Emby client implementation
β β βββ mpv/ # MPV IPC driver logic
β βββ tauri.conf.json # Tauri configuration
βββ docs/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, Oxfmt 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 | Oxlint |
| Testing | Rstest |
JellyPilot doesn't appear as a Jellyfin cast target
- Ensure you're logged in (check Operations Console shows "Connected").
- Refresh the Jellyfin web page after JellyPilot connects.
- Check Jellyfin Dashboard > Activity for the JellyPilot session.
- Emby support is focused on in-app library playback and remote control, not Jellyfin-style cast discovery.
MPV doesn't start
- Verify MPV is installed:
mpv --version. - Check MPV is in PATH (or set explicit path in Operations Console settings).
- Windows (Scoop): JellyPilot auto-resolves symlinks, but ensure the shim is valid.
- Check Operations Console > Player Bridge settings for detected path.
Video doesn't play
- Check your Jellyfin or Emby transcoding settings.
- Verify network connectivity to your Jellyfin or Emby server.
- Check Diagnostics in the Operations Console for error messages.
Connection lost
- JellyPilot 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 (Oxc 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.