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.
- 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
- 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)
- transcoding, shuffle, repeat modes, the works
- works over ssh (and tmux)
- fast and just kind of nifty really
- other media types (movies, tv shows)
- jellyfin-wide remote control and much more
- if there is a feature you'd like to see, please open an issue :)
jellyfin-tui is available as a package in the AUR. You can install it with your preferred AUR helper. Example:
paru -S jellyfin-tuijellyfin-tui is available as a package in Nixpkgs.
jellyfin-tui is available as a package in the Alpine Linux community repository.
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 .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 .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'
# Swap the play and pause icons
swap_play_pause: false
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 if enabled
# !!CAUTION!! - Enabling this will expose the URL of your Jellyfin instance to all Discord users!
discord_art: false
# 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.logClick 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.
"#rrggbb"(hex)"red","white","gray"(named)"auto"→ uses the extracted accent from album art"none"→ disables optional backgrounds (background,album_header_backgroundonly)
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. |
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"The "auto" accent color is derived from album art by default. You can disable this by setting
auto_color: falsein the config file. This will use the accent color defined in the theme instead for all ""auto"" usages.
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 customize
keymap:
ctrl-c: Quit
j: Down
k: Up
space: PlayPauseEach entry maps a key combination to an action.
Adding a new key does not remove existing bindings.
For example, if you want to add ctrl + s as an additional key for shuffling the queue, you can do:
keymap:
ctrl-s: ShuffleBoth ctrl + s and the default s will now trigger the Shuffle action.
If you bind a key that already exists, it replaces the previous action.
keymap:
ctrl-c: ResetNow ctrl + c will trigger the Reset action instead of quitting.
To unbind a particular keybinding, you can set its value to null.
keymap:
# the `Reset` action will now show (unbound) in the help page
ctrl-x: nullTo start with a completely empty keymap:
keymap_inherit: false
# only `Quit`, `Down` and `Up` will be bound
keymap:
ctrl-q: Quit
j: Down
k: UpSome actions accept parameters. It is important to use the correct syntax for these, which is
!ActionName "parameters":
keymap:
# seek 10 seconds forward or backward
ctrl-h: !Seek -10
ctrl-l: !Seek 10
# run a shell command, in this case detaching from tmux
q: !Shell "tmux detach"Only the bindings you define will exist.
Key syntax
The expected syntax format is modifier-modifier-key: ActionName. Modifiers can be ctrl, alt, or shift and can be
combined in any order. For example, ctrl-shift-a or shift-ctrl-a are both valid.
The key can be any single character, function key (e.g., F1, F2), or special key (e.g., Enter, Space).
ctrl-c: Quit
shift-enter: QueueTempBack
alt-j: Down
ctrl-left: ShrinkPane
ctrl-shift-s: GlobalShuffle
':': !Shell "notify-send hello"enter
esc
tab
backtab
left right up down
home end
pageup pagedown
delete backspace
spaceThere are only so many keys to bind, so some actions are hidden behind a popup. Press p to open it and ESC to close
it. To open the Global Popup, press Shift+p. The popup is context-sensitive and will show different options depending
on where you are in the program.
The Global Popup includes several toggleable preferences:
| Option | Description |
|---|---|
| Synchronize with Jellyfin (runs every 10 minutes) | Manually trigger a library synchronization with the Jellyfin server. This updates the local cache with any changes made on the server, such as new tracks, metadata updates, etc. |
| Run a Jellyfin task | Trigger any of the available Jellyfin background tasks, such as Library: Download missing lyrics or Media Analysis. Very useful for performing maintenance tasks without logging into the web interface. |
Switch to {large/small} artwork |
Toggles the cover art display size |
Use {track/album} |
Determines whether to use the track's own artwork or the album's artwork when both are available. Also respected when downloading tracks for offline use. |
| Theme | Opens the theme picker |
| Select music libraries | If you have multiple music libraries, you can choose which one(s) to include in your library view. |
| Repair offline downloads (could take a minute) | Checks the integrity of downloaded tracks and repairs any issues by re-downloading them from the server. Useful if you encounter problems with offline playback or if your library has changed significantly. |
| Stop downloading and abort queued | Immediately stops all ongoing downloads and clears the download queue. Useful if you need to quickly free up bandwidth or system resources, or if you accidentally initiated a large number of downloads. |
| Reset section widths | Resets the widths of all sections to their default values. |
Regular popups include options relevant to the current context. For example, in the discography view, you can choose the order in which albums are displayed:
Jellyfin-tui has a double queue similar to Spotify. You can add songs to the queue by pressing e or shift + enter.
Learn more about what you can do with the queue by pressing ? and reading through the key bindings.
You can shuffle from your entire library with the Global Shuffle feature. Open it with Ctrl+S, select from the options
it offers, and hit Play to start playing.
Jellyfin-tui registers itself as an MPRIS client, so you can control it with any MPRIS controller. For example,
playerctl.
In the Artists and Tracks lists you can search by pressing / and typing your query. The search is case-insensitive and
will filter the results as you type. Pressing ESC will clear the search and keep the current item selected.
You can search globally by switching to the Search tab. The search is case-insensitive and will search for artists, albums and tracks. It will pull everything without pagination, so it may take a while to load if you have a large library. This was done because jellyfin won't allow me to search for tracks without an artist or album assigned, which this client doesn't support.
Downloading music is very simple, just press d on a track, or album. More download options can be found in popups.
You can launch jellyfin-tui in offline mode by passing the --offline flag. This will disable all network access and
only play downloaded tracks.
A local copy of commonly used data is stored in a local database. This speeds up load times and allows you to use the program fully offline. Also, playing a downloaded track will play the local copy instead of streaming it, saving bandwidth.
Your library is updated in the background every 10 minutes. You will be notified if anything changes. Track metadata updates whenever you open a discography/album/playlist view in-place. You can also force an update in the global popup menu. Jellyfin is the parent, if you delete music on the server, jellyfin-tui will also delete it including downloaded files.
Due to the nature of the project and jellyfin itself, there are some limitations and things to keep in mind:
- jellyfin-tui assumes you correctly tag your music files. Please look at the jellyfin documentation on how to tag your music files. Before assuming the program is broken, verify that they show up correctly in Jellyfin itself.
- lyrics: jellyfin-tui will show lyrics if they are available in jellyfin. To scroll automatically with the song,
they need to contain timestamps. I recommend using
the LrcLib Jellyfin plugin and running
Download missing lyricsdirectly within jellyfin-tui (Global Popup > Run Jellyfin task > Library: Download missing lyrics), or alternatively the desktop application LRCGET, both by by tranxuanthang. If you value their work, consider donating to keep this amazing free service running.
Not all terminals have the features needed to cover every aspect of jellyfin-tui. While rare, some terminals lack sixel (or equivalent) support or have certain key event limitations. The following are tested and work well:
- kitty (recommended)
- iTerm2 (recommended)
- ghostty
- contour
- wezterm
- foot
The following have issues
- konsole, alacritty, gnome console, terminator (no sixel support and occasional strange behavior)





