MCPcopy Index your code
hub / github.com/dhonus/jellyfin-tui

github.com/dhonus/jellyfin-tui @v1.5.1

Chat with this repo
repository ↗ · DeepWiki ↗ · release v1.5.1 ↗ · + Follow
599 symbols 1,550 edges 29 files 128 documented · 21%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

jellyfin-tui

Jellyfin-tui is a (music) streaming client for the Jellyfin media server. Inspired by CMUS and others, its goal is to offer a self-hosted, terminal music player with all the modern features you need.

Features

  • stream your music from Jellyfin
  • sixel cover image, courtesy of ratatui-image
  • lyrics with autoscroll (Jellyfin > 10.9)
  • custom themes, color extraction from album art + smooth interpolated transitions + tinted variants
  • spotify-like double queue with order control, etc.
  • full offline mode with metadata caching, track downloads, background updates and slow network fallback
  • last.fm scrobbling, you need jellyfin-plugin-lastfm
  • multi-library support
  • vim-style keybindings
  • MPRIS integration
  • playlists (play/create/edit/reorder)
  • transcoding, shuffle, repeat modes, the works
  • remote control from the Jellyfin web UI or any other Jellyfin client
  • vertical layout for narrow terminals, resize panes with Ctrl+Up/Down
  • works over ssh (and tmux)
  • sleep timer
  • fast and just kind of nifty really

Planned features

  • other media types (movies, tv shows)
  • if there is a feature you'd like to see, please open an issue :)

Screenshots

image

Installation

Pre-built binaries

Pre-built binaries for Linux and macOS are available on the releases page. Download the binary for your platform, make it executable, and place it somewhere on your PATH.

Arch Linux

jellyfin-tui is available as a package in the AUR. You can install it with your preferred AUR helper. Example:

paru -S jellyfin-tui

Nix

jellyfin-tui is available as a package in Nixpkgs.

Alpine Linux

jellyfin-tui is available as a package in the Alpine Linux community repository.

Other Linux

Jellyfin-tui depends on libmpv2 (audio playback) and sqlite3 (offline caching), both of which should be available in your distribution's package manager. On Debian/Ubuntu based systems, you may need to install libmpv-dev and libssl-dev as well for building.

# If you're new to rust:
# install rust from https://rustup.rs and make sure ~/.cargo/bin is in your PATH (add this to ~/.bashrc or ~/.zshrc etc.)
export PATH=$PATH:~/.cargo/bin/

# Arch
sudo pacman -S mpv sqlite
# Ubuntu/Debian
sudo apt install mpv libmpv-dev sqlite3 libssl-dev
# clone this repository
git clone https://github.com/dhonus/jellyfin-tui
cd jellyfin-tui

# optional: use latest tag
git fetch --tags
git checkout $(git tag | sort -V | tail -1)

cargo install --path .

macOS

brew install mpv
git clone https://github.com/dhonus/jellyfin-tui
cd jellyfin-tui
# add exports to your shell profile (~/.zshrc etc.)
export LIBRARY_PATH="$LIBRARY_PATH:$(brew --prefix)/lib"
export PATH=$PATH:~/.cargo/bin/
cargo install --path .

Configuration

When you run jellyfin-tui for the first time, it will guide you through creating a configuration file. You can authenticate using either username/password, password file, or jellyfin quick connect. Each of these options then uses locally stored auth tokens for future logins.

The program prints the config location when run. On linux, the configuration file is located at ~/.config/jellyfin-tui/config.yaml. Feel free to edit it manually if needed.

servers:
  - name: Password Server
    url: 'https://jellyfin.example.com'
    username: 'username'
    password: 'imcool123'
    default: true # Add to skip server picker on startup. Use --select-server to override
  - name: Quick Connect Server
    url: 'http://localhost:8096'
    quick_connect: true # use jellyfin quick connect
  - name: Password File Server
    url: 'http:/jellyfin.example2.com'
    username: 'username'
    password_file: /home/myusername/.jellyfin-tui-password # use a file containing the password

# All following settings are OPTIONAL. What you see here are the defaults.

# Show album cover image
art: true
# Save and restore the state of the player (queue, volume, etc.)
persist: true
# Grab the primary color from the cover image (false => uses the current theme's `accent` instead)
auto_color: true
# Time in milliseconds to fade between colors when the track changes
auto_color_fade_ms: 400

# Always show the lyrics pane, even if no lyrics are available
lyrics: 'always' # options: 'always', 'never', 'auto'

# Layout mode — 'auto' switches to vertical below vertical_threshold columns
layout: auto # options: 'auto', 'vertical', 'horizontal'
vertical_threshold: 100 # columns; only used when layout is 'auto'

# Swap the play and pause icons
swap_play_pause: false
# Custom symbols — useful for Nerd Font users. Each character of `spinner` is one animation frame.
symbols:
  favorite: "♥"
  shuffle: "⤮"
  play: "►"
  pause: "⏸︎"
  sleep: "⏾"
  downloaded: "⇊"
  queued: "◴"
  lyrics: "♪"
  spinner: "◰◳◲◱"
  separator: "›"
  disc: "○"

rounded_corners: true

transcoding:
  bitrate: 320
  # container: mp3

# Discord Rich Presence. Shows your listening status on your Discord profile if Discord is running.
discord: APPLICATION_ID
# Displays album art on your Discord profile.
# "off"          - no art (default)
# "musicbrainz"  - fetch from MusicBrainz/Cover Art Archive. Does not expose your server URL, but may occasionally miss.
# "local"        - use your Jellyfin server  !!CAUTION!! exposes your Jellyfin server URL to all Discord users
discord_art: "musicbrainz"
# Sets the text shown in your Discord status. (Listening to {})
# name: jellyfin-tui
# state: artist
# details: track title
discord_status: "state"

# Customize the title of the terminal window
window_title: true # default -> {title} – {artist} ({year})
# window_title: false # disable
# Custom title: choose from current track's {title} {artist} {album} {year}
# window_title: "\"{title}\" by {artist} ({year}) – jellyfin-tui"

# Options specified here will be passed to mpv - https://mpv.io/manual/master/#options
mpv:
  replaygain: album
  af: lavfi=[loudnorm=I=-23:TP=-1]
  no-config: true
  log-file: /tmp/mpv.log
  # Load custom Lua scripts. Any script in ~/.local/share/jellyfin-tui/mpv-scripts/ is also loaded automatically.
  scripts:
    - /path/to/script.lua

Theming

Click to reveal theming documentation

Jellyfin-tui comes with several built-in themes in both light and dark variants. You can switch between themes in the global popup.

You can also define your own custom themes in the config by selecting a base theme and overriding any colors you want. Custom themes are hot-reloaded when you save the config file.

accent_color file

The accent color gets written to a file each time it changes. It is located in the DATA_DIR. (for example ~/.local/share/jellyfin-tui/accent_color on linux) and contains the #HEX rgb color. Use it with pywal or similar tools.

Color formats

  • "#rrggbb" (hex)
  • "red","white","gray" (named)
  • "auto" → uses the extracted accent from album art
  • "tinted" → keeps the inherited base color but blends it slightly towards the album accent (strength controlled by tint_strength)
  • "tinted #rrggbb" / "tinted:#rrggbb" → same as above but with an explicit base color
  • "none" → disables optional backgrounds (background,album_header_background only)

Overridable keys

Full list of keys

Key Description
background Main background color. Optional — none uses terminal bg.
foreground Primary text color.
foreground_secondary Secondary text (artists in player, ...).
foreground_dim Dimmed text for less important UI elements.
foreground_disabled Disabled or unavailable UI elements, disliked tracks.
section_title Titles of sections like Albums, Artists, etc.
accent Fallback color for "auto", applied when album art isn't available or if auto_color is disabled.
border Normal border color.
border_focused Border color when a widget is focused. "auto" uses primary (album) color.
selected_active_background Background of the currently selected row the the active section.
selected_active_foreground Text color of the selected row in the active section.
selected_inactive_background Background of selected rows in inactive sections.
selected_inactive_foreground Foreground of selected rows in inactive sections.
scrollbar_thumb Scrollbar handle color.
scrollbar_track Scrollbar track color.
progress_fill Played/filled portion of progress bars.
progress_track Unfilled portion of progress bars.
tab_active_foreground Text color of the active tab.
tab_inactive_foreground Text color of inactive tabs.
album_header_background Background for album/artist header rows (optional).
album_header_foreground Foreground for album/artist header rows.
tint_strength 0.01.0 float. Controls how much "tinted" colors shift towards the album accent. Stock 0.0, default tinted themes use 0.06.

Example themes

themes:
  - name: "Transparent Light"
    base: "Light"

    # remove background
    background: "none"

    # make active tab text use album accent color
    tab_active_foreground: "auto"

  - name: "Monochrome Dark (Tweaked)"
    base: "Monochrome Dark"

    # remove background and album header backgrounds
    background: "none"
    album_header_background: "none"

    # make progress bar follow album accent
    progress_fill: "auto"

    # high contrast row selection
    selected_active_background: "#eeeeee"
    selected_active_foreground: "black"

  - name: "Gruvbox Dark (Tinted)"
    base: "Gruvbox Dark"

    # surfaces shift subtly towards the album accent color
    tint_strength: 0.08
    background: "tinted"                       # inherits Gruvbox's background and tints it
    border: "tinted #3a3a3a"                   # explicit base color, tinted towards accent
    selected_inactive_background: "tinted"
    scrollbar_thumb: "tinted #808080"
    progress_track: "tinted"

Built-in tinted themesTinted Dark and Tinted Light are available out of the box and apply the same treatment to the standard dark/light palettes. Switch to them from the theme picker.

The "auto" accent color is derived from album art by default. You can disable this by setting

auto_color: false

in the config file. This will use the accent color defined in the theme instead for all ""auto"" usages.


Keymap / Custom key bindings

jellyfin-tui supports fully customizable key bindings via the config file.

You can:

  • add new bindings
  • override existing bindings
  • or disable defaults entirely

Press ? inside jellyfin-tui to see all the available actions and your current bindings. Use the action names exactly as shown there when defining your keymap.

The Help page is the authoritative reference for all actions and bindings.

How to

Extension points exported contracts — how you extend this code

Searchable (Interface)
Trait abstracting over anything that can be searched by name. This includes Artists, Albums, Tracks, Playlists, etc. [6 …
src/helpers.rs
Backend (Interface)
(no doc) [3 implementers]
crates/media-controls/src/lib.rs
LogErr (Interface)
(no doc) [1 implementers]
src/helpers.rs

Core symbols most depended-on inside this repo

resolve
called by 183
src/themes/theme.rs
as_str
called by 138
src/mpv.rs
close_popup
called by 71
src/popup.rs
get_id_of_selected
called by 57
src/keyboard.rs
log_dbg
called by 52
src/helpers.rs
position
called by 45
crates/media-controls/src/lib.rs
reposition_cursor
called by 44
src/keyboard.rs
set_generic_message
called by 37
src/popup.rs

Shape

Method 380
Function 120
Class 57
Enum 39
Interface 3

Languages

Rust100%

Modules by API surface

src/client.rs76 symbols
src/keyboard.rs68 symbols
crates/media-controls/src/linux.rs54 symbols
src/tui.rs48 symbols
src/database/extension.rs36 symbols
src/helpers.rs35 symbols
src/themes/theme.rs34 symbols
src/popup.rs32 symbols
crates/media-controls/src/lib.rs32 symbols
src/mpv.rs28 symbols
src/database/database.rs25 symbols
crates/media-controls/src/macos.rs18 symbols

For agents

$ claude mcp add jellyfin-tui \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page