Files
jellybloom/README.md
T
2026-05-21 00:31:05 +03:00

166 lines
9.0 KiB
Markdown

<div align="center">
# Jellybloom
**A desktop media client for Jellyfin that actually feels good to use.**
Built for people who own their own servers. No accounts, no subscriptions, no telemetry, no gatekeepers between you and your library.
<br>
<img src="https://img.shields.io/badge/version-0.1.0-6B8AFF?style=flat-square&labelColor=282C33" alt="Version">
<img src="https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux-6B8AFF?style=flat-square&labelColor=282C33" alt="Platform">
<img src="https://img.shields.io/badge/React-19-61DAFB?style=flat-square&logo=react&logoColor=white" alt="React">
<img src="https://img.shields.io/badge/Tauri-v2-24C8D8?style=flat-square&logo=tauri&logoColor=white" alt="Tauri">
<img src="https://img.shields.io/badge/license-CC0_Public_Domain-6B8AFF?style=flat-square&labelColor=282C33" alt="License">
</div>
<br>
## Why Jellybloom?
You already run a Jellyfin server. You already own the media. So why does using it still feel like navigating a web app designed by committee?
Jellybloom is a complete reimagining of the media client experience. It is not a reskin of jellyfin-web and it is not a fork. It is a ground-up desktop application that talks directly to your Jellyfin server and makes browsing, discovering, and watching actually pleasant. Fast, dense, responsive, and fully under your control.
No cloud dependencies. No data collection. No feature gates. No one profits from your watch history except you.
<br>
## What it does
### Browse your library
The home page is built from shelves you can curate yourself, or you can let the app suggest rows based on what you actually watch. The poster grid uses virtualized scrolling so it stays smooth even with thousands of items. A right-click on any poster opens a quick-look modal so you can peek at details without losing your scroll position. A notification bell in the header tracks new episodes and movies, deduplicated by series so a full-season drop does not flood the list.
Search is fuzzy and unified across titles, people, and collections. Saved searches stick around if you find yourself looking for the same things repeatedly.
### Watch in a player that cares
The player is built on Vidstack with hls.js, and the entire chrome layer is custom. Subtitles get special attention: ASS and SSA render natively through libass-wasm so styled fansubs look exactly as intended. SRT, WebVTT, and plain text work too. You can search OpenSubtitles from inside the player, adjust size, font, outline, color, background opacity, and positioning.
Playback features include bookmarks with notes, A-B looping, chapter navigation, trickplay thumbnails on the scrubber, speed control from 0.5x to 3x, a picture filter for badly-encoded sources, and an audio graph with a compressor and parametric EQ. Audio passthrough lets your receiver handle decoding when it can. A quality menu switches streams on the fly. The resume prompt picks up where you left off but asks first so you do not spoil a cold open.
The end card shows the next episode or a related title as the credits roll. The mini player pops out to a small floating window. A sleep timer fades out after your chosen duration. A "still watching?" prompt gently checks in after a few episodes so your stats do not run away from you. Downloads save movies and episodes for offline playback via blob URLs. Cast sends playback to another Jellyfin session on your network. SyncPlay lets you watch together with friends by joining or creating a group that locks playback state.
Trakt.tv scrobbling is optional and uses device-code auth — no browser redirects, no OAuth callbacks. Every keyboard action can be rebound from settings.
### Rich detail pages
Every title gets a detail page that pulls from multiple sources. The hero shows a backdrop, poster, and logo overlay from Jellyfin or TMDB, plus rating badges and action buttons. Cast and crew are clickable, with in-library matches highlighted in a person's filmography. The composer gets their own block. Awards come from Wikidata. Filming locations are mapped with Leaflet.
Reception aggregates every available rating source: IMDb, TMDB, Rotten Tomatoes, Metacritic, plus your own. Reviews come from TMDB. Videos include trailers and clips from YouTube. Trivia comes from Wikipedia. Tech specs show codec, container, resolution, HDR format, and audio channels, with badge icons for Dolby Vision, Atmos, DTS:X, and others. The collection strip shows franchise entries. Series status shows air days, next episode, season count, and production state.
Anime filler detection flags filler and mixed-canon episodes based on a bundled dataset. If you have multiple versions of a file, a selector lets you pick. The watch timeline draws from your diary. The personal section keeps your ratings, rewatch counts, and notes local. The diary lets you log watches with a date, rating, and rewatch flag, and export to Markdown, JSON, or Letterboxd CSV.
### Discover what you do not have
The Discover page finds things you do not already own. It needs a free TMDB API key and respects your region and adult-content preference. There is a personalized spotlight based on your top genre, a trending pick, mood chips that resolve to filtered rows, a roulette for random highly-rated titles, decade strips, canonical lists, an "on this day" feature, and a library gap finder that shows the highest-rated missing titles in genres you already watch.
You can browse by genre, language, studio, or network with inline expansion on each tile, or use advanced filters for year range, rating, vote count, and sort order.
### Profile and stats
The profile page tracks your watch streak, genre breakdown, year-in-review summary, personally top-rated titles, and recent diary entries.
### Settings
The settings page covers server connection with support for multiple servers and a live dashboard, playback defaults, audio and subtitle preferences, display options including density, accent color, UI scale, and reduced motion, home page row toggles, detail page section toggles, episode defaults, discovery preferences, TMDB and Fanart.tv keys, Trakt.tv connection, Sonarr and Radarr configuration with multiple instances and override rules, personal data management, privacy controls, and full keyboard shortcut rebinding.
<br>
## Accessibility
Jellybloom targets WCAG 2.2 AAA conformance because a media client that only works for some people is not really a media client.
| Area | Details |
|:-----|:--------|
| **Semantic HTML** | Proper landmarks, ARIA roles for menus, dialogs, tabs, and status regions |
| **Full keyboard navigation** | Every interactive element reachable and operable without a mouse |
| **Focus management** | Visible focus indicators on all controls, focus traps in modals with restore on close |
| **High contrast** | All themes meet AAA contrast ratios (7:1+ for normal text) |
| **Reduced motion** | Respects prefers-reduced-motion — all animations disabled when active |
| **Screen readers** | ARIA live regions for dynamic content, proper labels on icon-only buttons |
| **Touch targets** | All interactive controls meet 24x24px minimum |
<br>
## Getting started
### Prerequisites
- Node.js 18+
- Rust (latest stable)
- Tauri v2 prerequisites for your platform
### Development
```bash
git clone https://git.lashman.live/lashman/jellybloom.git
cd jellybloom
npm install
```
```bash
# Browser dev server
npm run dev
# Desktop dev
npm run tauri:dev
# Production build
npm run tauri:build
```
<br>
## Technology stack
| | Layer | Technology |
|:--|:--|:--|
| **Runtime** | Desktop shell | [Tauri v2](https://tauri.app/) |
| **Frontend** | UI framework | React 19, TypeScript, Vite |
| **Styling** | CSS | Tailwind CSS 4 |
| **State** | Management | Zustand |
| **Data** | Fetching and caching | TanStack Query |
| **Lists** | Virtualization | TanStack Virtual |
| **Playback** | Media engine | Vidstack, hls.js |
| **Subtitles** | Rendering | libass-wasm |
| **Animation** | Transitions | Framer Motion |
| **Maps** | Locations | Leaflet |
| **Search** | Fuzzy matching | Fuse.js |
| **Primitives** | Accessibility | Radix UI |
<br>
## Project structure
```
jellybloom/
├── src/
│ ├── api/ API clients (Jellyfin, TMDB, Fanart, etc.)
│ ├── components/ UI components (player, detail, discover, layout)
│ ├── hooks/ Data hooks and player logic
│ ├── lib/ Utilities, formatters, device profile
│ ├── pages/ Route pages
│ ├── stores/ Zustand stores
│ └── types/ TypeScript declarations
├── src-tauri/ Rust backend
│ ├── src/
│ ├── capabilities/
│ └── icons/
├── public/ Static assets
├── package.json
├── vite.config.ts
└── tsconfig.json
```
<br>
## License
Dedicated to the public domain under [CC0 1.0 Universal](LICENSE).
No copyright, no restrictions, no permission needed. Take it, use it, change it, share it. The culture belongs to everyone.