This commit is contained in:
2026-05-21 00:27:21 +03:00
parent 3803aca188
commit 450f29dcf5
+26 -122
View File
@@ -1,153 +1,57 @@
# Jellybloom # Jellybloom
a desktop media client for Jellyfin, built because nobody should have to rent back their own culture from a server they already run A desktop media client for Jellyfin. i built this because i think nobody should have to rent back their own culture from a server they already run.
## what it does This code is released under CC0 — take it, change it, run your own fork, or ignore it entirely. No attribution needed, no permission required. The culture belongs to everyone.
Jellybloom is a React + TypeScript + Vite + Tauri app that talks to your Jellyfin server and makes browsing, discovering, and watching actually pleasant. it is not a fork of jellyfin-web. it is not a skin. it is a complete reimagining of how a personal media library should feel - fast, dense, and yours. ## What Jellybloom does
### browse Jellybloom is a complete alternative to the default Jellyfin web client, not a reskin. It's a React + TypeScript + Vite app wrapped in Tauri, and it talks directly to your Jellyfin server over the same APIs the official client uses. The difference is in the details — everything is denser, faster, and built around the idea that your library is yours to explore however you want.
- **movies, shows, music, playlists, live TV** - the usual stuff, but with a poster-grid that doesn't make your scroll wheel cry ### Browsing and search
- **unified search** - fuzzy matching across titles, people, and collections. saved searches stick around if you want them to
- **smart shelves** - curate your own rows on the home page (or let the app suggest some based on what you actually watch)
- **notification bell** - new episodes and movies land here, deduplicated by series so a full-season drop doesn't flood you
- **quick look** - right-click any poster for a peek without losing your scroll position
### player 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. There's a unified search that fuzzy-matches across titles, people, and collections, with saved searches if you find yourself looking for the same things repeatedly. The poster grid uses virtualized scrolling so it stays smooth even with thousands of items, and 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 doesn't flood the list.
the player is where most of the love went. it is built on **Vidstack** + **hls.js** with a custom chrome layer: ### The player
- **subtitle rendering** - native ASS/SSA via **libass-wasm**, so styled fansubs look exactly like they're supposed to. also supports SRT, VTT, and plain text Most of the work went into the player. It's built on Vidstack with hls.js for HLS playback, and the entire chrome layer is custom.
- **subtitle search** - search and download from OpenSubtitles without leaving the player
- **subtitle styling** - size, font, outline, color, background opacity, positioning
- **bookmarks** - drop a pin at any moment with a note. bookmarks show up as dots on the scrubber
- **A-B loop** - loop a section for study, reference, or that one perfect joke
- **chapters** - jump between chapters from the scrubber or a side panel
- **trickplay thumbnails** - hover the scrubber to see exactly where you are
- **speed control** - 0.5x to 3x, because some shows deserve it and others really don't
- **picture filter** - brightness, contrast, saturation, hue, and gamma. useful for badly-encoded sources
- **audio graph** - a lightweight compressor + parametric EQ chain for when the mix is too quiet or too loud
- **audio passthrough** - let your receiver handle decoding when it can
- **quality menu** - switch streams on the fly (or let the server decide)
- **track menus** - pick audio and subtitle streams without leaving fullscreen
- **resume prompt** - picks up where you left off, but asks first so you don't spoil the cold open
- **up next / end card** - shows the next episode or related title as the credits roll
- **mini player** - pop out to a small floating window and keep watching while you do other things
- **sleep timer** - fades out after your chosen duration so you don't wake up three seasons later
- **"still watching?" prompt** - gently checks if you're still there after a few episodes (prevents runaway binge stats)
- **downloads** - save a movie or episode for offline playback. stored as a blob URL in the session
- **cast** - send playback to another Jellyfin session on your network
- **SyncPlay** - watch together with friends. join or create a group, and playback stays locked
- **Trakt.tv scrobbling** - optionally logs what you watch to Trakt (device-code auth, no redirect nonsense)
- **keyboard shortcuts** - fully customizable. every action in the player and app can be bound to whatever key combo you want
### detail pages Subtitles get special attention. The app renders ASS and SSA natively through libass-wasm, which means 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. If the encode is bad, there's a picture filter for brightness, contrast, saturation, hue, and gamma. An audio graph gives you a compressor and parametric EQ for when the mix is too quiet or too loud, and you can pass through audio to your receiver when it's capable.
every title gets a rich detail page that pulls from multiple sources: Playback features include bookmarks with notes (shown as dots on the scrubber), A-B looping, chapter navigation, trickplay thumbnails on hover, speed control from 0.5x to 3x, and a sleep timer. There's a "still watching?" prompt that gently checks in after a few episodes so your stats don't run away from you. The resume prompt picks up where you left off but asks first, so you don't spoil a cold open. The end card shows the next episode or a related title as the credits roll. You can pop out a mini player to keep watching while doing other things, cast to another Jellyfin session on your network, or join a SyncPlay group to watch together with friends.
- **hero** - backdrop, poster, logo overlay (from Jellyfin or TMDB), rating badges, action buttons Downloads work via blob URLs in the session, so you can save a movie or episode for offline playback. Trakt.tv scrobbling is optional and uses device-code auth — no browser redirects, no OAuth callbacks. Every keyboard action in the player and app can be rebound from the settings.
- **cast & crew** - click any person for their filmography, with in-library matches highlighted
- **crew grid** - directors, writers, producers, with job labels
- **composer block** - because the score matters and nobody else puts it front and center
- **awards** - pulled from Wikidata. Oscars, BAFTAs, Golden Globes, and more
- **filming locations** - mapped with Leaflet. see where it was shot
- **where to watch** - streaming availability by region, via TMDB
- **reception** - aggregate of every rating source available (IMDb, TMDB, Rotten Tomatoes, Metacritic, your own)
- **reviews** - pulled from TMDB
- **videos** - trailers and clips from YouTube
- **trivia** - production notes and keywords from Wikipedia
- **tech specs** - codec, container, resolution, audio channels, HDR format. media tech badge icons for Dolby Vision, Atmos, DTS:X, etc.
- **collection strip** - franchise entries with the current title highlighted
- **series status** - air days, next episode, season count, whether it's still in production
- **episode extras** - guest stars, production codes, absolute numbering
- **anime filler detection** - flags filler and mixed canon episodes based on a bundled dataset
- **versions selector** - when you have multiple files for one title, pick the one you want
- **watch timeline** - your personal history with this title, drawn from the diary
- **personal section** - your own rating, rewatch count, and notes. this data stays local
- **diary** - log watches with a date, rating, and rewatch flag. export to Markdown, JSON, or Letterboxd CSV
- **request button** - if you don't have it, request it from Radarr or Sonarr without leaving the page
### discover ### Detail pages
the Discover page is for finding things you don't already own. it needs a TMDB API key (free) and respects your region and adult-content preference: Every title gets a rich 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 because the score matters. 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, trailers, production trivia, and tech specs (codec, container, resolution, HDR format) are all there. There's a collection strip for franchises, a series status block for air days and upcoming episodes, and anime filler detection 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, and the personal section keeps your ratings, rewatch counts, and notes local.
- **tonight hero** - a personalized spotlight based on your top genre ### Discover
- **spotlight hero** - trending pick of the day
- **mood chips** - ten vibes ("cosy," "chaotic," "melancholic") that resolve to a filtered row
- **roulette** - spin for a random highly-rated title from your chosen kind
- **decade strips** - "the 90s," "the 80s," etc. with interleaved movie and TV picks
- **canonical lists** - "top rated," "cult classics," "upcoming"
- **on this day** - titles that premiered on today's date
- **library gap finder** - shows the highest-rated missing titles in genres you already watch
- **browse grid** - explore by genre, language, studio, or network. each tile expands inline
- **advanced filters** - year range, rating, vote count, genre, watch region, sort order
### profile & stats The Discover page is for finding things you don't already own. It needs a free TMDB API key and respects your region and adult-content preference. There's 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.
- **watch streak** - consecutive days with logged play activity ### Profile and stats
- **genre breakdown** - pie chart of what you actually watch
- **year in review** - hours watched, top genres, longest binge
- **top rated** - your personally highest-rated titles
- **recent diary** - last few logged watches
### settings The profile page tracks your watch streak, genre breakdown, year-in-review summary, personally top-rated titles, and recent diary entries. The diary itself lets you log watches with a date, rating, and rewatch flag, and export to Markdown, JSON, or Letterboxd CSV.
a lot of care went into making everything configurable without drowning you in toggles: ### Settings
- **server** - connect to one or many Jellyfin servers. switch between them without re-logging The settings page is split into sections: server connection (with support for multiple servers and a live dashboard), playback defaults, audio and subtitle preferences, display options (density, accent color, UI scale, 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 (including multiple instances and override rules), personal data management, privacy controls, and keyboard shortcut rebinding.
- **server dashboard** - live stats: version, uptime, active streams, who's transcoding
- **playback** - autoplay, resume threshold, default audio language, subtitle language, subtitle size
- **audio & subtitles** - default behaviors, search preferences, styling defaults
- **display** - density (compact / comfortable), accent color, UI scale, reduced motion
- **home page** - toggle rows, pin smart shelves, hide adult content
- **detail page** - turn on/off sections you don't care about (trivia, filming locations, awards, etc.)
- **episodes** - default sort order, show/hide filler chips, absolute numbering
- **discovery** - region, hide adult, default filters
- **TMDB** - your own API key (optional built-in fallback)
- **Fanart.tv** - API key for richer artwork
- **Trakt.tv** - connect, sync watchlist, enable scrobbling
- **Sonarr & Radarr** - connect multiple instances (default + 4K tiers), set override rules per request
- **personal** - manage your ratings, rewatch counts, and diary
- **privacy** - clear caches, export data, delete everything
- **shortcuts** - rebind every keyboard action
- **about** - version, stack, acknowledgements
### the little things ## Stack
- **sidebar pinning** - pin it open or let it auto-hide React 19 and TypeScript, Vite and Tailwind CSS, Tauri 2 for the desktop shell, Zustand for state, TanStack Query for data fetching, TanStack Virtual for lists, Vidstack and hls.js for playback, libass-wasm for subtitles, Framer Motion for transitions, Leaflet for maps, Fuse.js for fuzzy search, and Radix UI for accessible primitives.
- **window controls** - minimize, maximize, close. the whole app is a drag region except the buttons
- **offline banner** - gentle notice when the server is unreachable
- **toast system** - non-intrusive feedback for actions
- **error boundary** - catches crashes and shows a recoverable screen instead of a white page
- **reduced motion** - respects the system preference
- **density modes** - compact for power users, comfortable for everyone else
## stack ## Dev
- **React 19** + **TypeScript** ```
- **Vite** + **Tailwind CSS**
- **Tauri 2** - desktop shell (Windows, macOS, Linux)
- **Zustand** - state management
- **TanStack Query** - data fetching and caching
- **TanStack Virtual** - virtualized lists
- **Vidstack** + **hls.js** - media playback
- **libass-wasm** - subtitle rendering
- **Framer Motion** - transitions and gestures
- **Leaflet** - maps
- **Fuse.js** - fuzzy search
- **Radix UI** - accessible primitives
## dev
```bash
npm install npm install
npm run dev # browser dev server npm run dev # browser dev
npm run tauri:dev # desktop dev npm run tauri:dev # desktop dev
npm run build # production web build npm run build # production web build
npm run tauri:build # production desktop build npm run tauri:build # production desktop build
``` ```
## license ## License
CC0 - this code is a common resource. take it, modify it, run your own fork, or don't. no attribution required, no permission needed. the culture belongs to everyone. CC0. This code is a common resource. The culture belongs to everyone.