A modern web application to track your Plex watchlist and organize titles by airing status or media type.
- 🔐 Plex OAuth Authentication - Secure login with your Plex account
- 📺 Watchlist Management - View movies and shows from your Plex watchlist
- 📊 Smart Grouping - Titles organized by:
- Currently Airing
- Not Yet Aired
- Recently Ended
- Finished Airing
- 🎛️ View Controls - Floating controls for filters, sorting, and grouping:
- All, Movies, TV Shows, Anime, Anime Movies
- Airing date, title, or rating / popularity sorting
- Airing-date or media-type grouping
- 🌓 Theme Support - Light, Dark, and System themes
- 🔄 Auto-refresh - Manual and automatic watchlist updates
- 📱 Responsive Design - Beautiful UI for mobile, tablet, and desktop
- React 19
- Zustand - Client state management
- Tailwind CSS v4 - Styling
- Rsbuild - Build tool
- Biome - Linter and formatter
Install the dependencies:
bun installStart the dev server, and the app will be available at http://localhost:3000:
bun run devBuild the app for production:
bun run buildPreview the production build locally:
bun run previewRun the linter:
bun biome check src/Auto-fix linting issues:
bun biome check --write src/- Sign in with your Plex account using OAuth
- The app fetches your full watchlist from Plex
- Titles are automatically classified as Movies, TV Shows, Anime, or Anime Movies
- Membership updates every 15 minutes while visible and online. Details reuse a 24-hour cache; active schedules update every 15 minutes. Manual refresh reloads all data.
- Switch between light and dark themes based on your preference
- Cached data renders after IndexedDB hydration with no Plex downloads until due. On a cold load, complete membership renders before enrichment finishes.
- The cache stores only card/grouping fields, freshness timestamps, and the owning account ID. Schema version 2 rejects old unscoped caches, requiring one fresh sync after upgrade.
- Requests have a 15-second timeout, run with at most four concurrent title downloads, and cancel when hidden, offline, or signed out. Automatic failures wait 15 minutes before retrying; manual refresh bypasses this wait.
- Failed or incomplete downloads preserve usable cached data. IndexedDB write ordering prevents an older write from restoring signed-out data, and hydration completion does not write over a cache after a failed read.
- Plex episode dates are an estimate of airing status. The latest known episode may not be the season finale.
- Filter categories are exact and non-overlapping: anime uses Plex genre metadata when available, then falls back to the media type so every title has one category.
- The floating view controls use the round button as the only close affordance while open; outside clicks hit a transparent backdrop that closes the panel without clicking the watchlist underneath.
- The watchlist API is paginated; keep pagination intact so "All" really means the full watchlist.
- Use
bun run test,bun run lint, andbun run buildbefore shipping changes.
For a mounted browser regression check, start the local app signed out and evaluate scripts/browser-check.js in its browser console. It uses fixture responses to check cold rendering, offline cancellation, freshness, manual refresh, cached error recovery, keyboard controls, and sign-out. It does not contact Plex.