Back to Building

FolioFin

Native Linux Jellyfin Book Reader

Tauri Rust React TypeScript Tailwind CSS epub.js PDF.js Framer Motion

Overview

FolioFin is a native Linux desktop reading client for Jellyfin media servers. If you self-host books on Jellyfin, FolioFin gives you a dedicated reader app — library browsing, EPUB/PDF/CBR reading, and reading progress that syncs back to your server.

Built with Tauri v2 and React, it runs as a native WebKitGTK window with no Electron overhead.

Why

Jellyfin has great apps for video and music, but its book support on Linux is an afterthought. The web UI is functional but not built for reading. FolioFin fills that gap: a focused, native reading experience that treats your book library as a first-class collection.

Features

Library

  • Connects to any Jellyfin server with username/password auth
  • Grid and list views with cover art, search, and sort
  • Collapsible sidebar navigation

Reader

  • EPUB — epub.js with paginated flow, dark / light / sepia themes, adjustable font size, font family, and margins
  • PDF — PDF.js with dark invert mode for comfortable night reading
  • CBR/CBZ — comic archive support via libarchive.js (WASM) and JSZip
  • Table of contents panel and reader settings panel

Sync

  • Reading progress synced to Jellyfin's playback API so position is preserved across sessions
  • Local fallback in localStorage for offline use

Architecture

Tauri v2 (Rust)
  └── WebKitGTK webview
        └── React 19 + TypeScript + Vite
              ├── Tailwind CSS v4 (via @tailwindcss/vite)
              ├── Zustand v5 — persisted global state
              ├── Framer Motion — screen transitions & animations
              ├── epub.js — EPUB rendering
              ├── pdfjs-dist v5 — PDF rendering
              └── libarchive.js — CBR comic extraction

All Jellyfin API calls are centralised in src/services/jellyfin.ts. The Zustand store (src/store/index.ts) manages auth state, library cache, and reader settings, persisted in localStorage.

Design

Deep dark theme built around CSS custom properties:

  • Base: #08080f near-black background
  • Primary: #7c3aed violet-purple for interactive elements
  • Accent: #06b6d4 cyan for highlights and progress
  • Glass-morphism cards with backdrop-filter blur
  • Framer Motion page transitions between library → detail → reader screens

Navigation Flow

Library screen
  → (click book tile) → Detail screen
  → (click Open Reader) → Reader screen
  → (back) → Detail → (back) → Library

Jellyfin Quirks Solved

Jellyfin's book API has some non-obvious edge cases:

  • HasPrimaryImage is null on some servers — cover detection uses ImageTags?.Primary instead
  • MediaSources is always empty for books — format detection falls back to the Path file extension
  • CBR comic files (Spider-Man Reign) required libarchive.js WASM since JSZip doesn't handle RAR archives

comments