Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

Listen is a native desktop music player for Linux and Windows. It plays music from your own server, from YouTube Music, from folders on your computer and from internet radio, all in one queue. This page explains what it is, what it can do and how this guide is organised.

What Listen is

Listen is written in Rust. It has no web view and no Electron runtime: it is one small program that starts quickly and keeps memory use low. The interface is drawn with iced and audio is played by mpv.

Its layout follows Feishin closely, so if you have used Feishin you will find the home feed, the album, artist and genre pages, the command palette, the full-screen player and the settings where you expect them. Listen is a separate program written from scratch, and it can import your Feishin settings (see Importing from Feishin).

Where the music comes from

SourceNotes
Navidrome and other OpenSubsonic serversServer address, user name and password. Gonic and Airsonic-style servers work too.
JellyfinLogin or Quick Connect. Servers on your network are found automatically. Music libraries only.
YouTube MusicUnofficial. Uses your own account through a browser you are signed in with. See YouTube Music.
Local foldersTags and cover art are read from the files.
Internet radioStations you add yourself. See Internet radio.

You can add several servers and switch between them, and one queue can hold songs from different sources. See Connecting your music.

What it adds to a player

  • Gapless playback with ReplayGain, an equalizer, a compressor, speed and pitch control and a choice of output device.
  • Beat-matched DJ transitions between songs (DJ transitions) and an optional AI DJ that picks sets and talks between them (AI DJ).
  • Synced lyrics, a visualizer, music videos for YouTube Music songs and DLNA casting to speakers and TVs.
  • Offline downloads from your own server, listening history with statistics, playlists and smart playlists.
  • Media keys, global hotkeys, a tray icon, Discord status, a remote-control web page and a built-in MCP server.
  • 32 built-in themes, custom themes and 17 interface languages.
  • A built-in updater that installs new releases from the project’s public GitHub page.

What Listen does not do

  • It does not provide any music. It plays what your servers, files and accounts give you access to.
  • It sends no telemetry and has no account of its own. See Privacy and security.
  • It does not download YouTube Music songs for offline use.

Note: Listen is an independent project. It is not affiliated with or endorsed by Google, YouTube, Navidrome, Jellyfin or Feishin.

How to read this guide

If you are new, read the Getting started chapters in order: Installation, First start, Connecting your music, and YouTube Music if you use it. The chapters under Using Listen and Playback describe everyday use. Reference lists every setting, MCP tool and command-line option, and Development is for people who want to build or change Listen.

If you want to look around before connecting anything, start the app with listen --demo (see Installation).

Installation

This page explains how to install Listen on Windows, Fedora and other Linux distributions, and how to try it without a server. Download all packages from the project’s Releases page on GitHub (the latest release is the one marked “Latest”).

Windows 10 and 11

  1. Download Listen-Setup-<version>.exe and run it.
  2. Windows SmartScreen may say the app is unrecognised, because the installer is not code-signed yet. Click More info, then Run anyway.
  3. Follow the installer. You can tick an option to create a desktop icon, and the last page offers to start Listen.

The installer installs for your user only, into %LOCALAPPDATA%\Programs\Listen, and needs no administrator rights. A Start menu entry is always created.

Note: Some antivirus programs find it unusual that Listen can read a browser’s YouTube sign-in. Listen reads only the cookies of youtube.com and music.youtube.com, only when you choose a browser for YouTube Music, and sends them nowhere but YouTube. See YouTube Music.

Helper programs

Listen plays through three separate open-source programs:

ProgramUsed forwinget ID
mpvPlaying audio and video (always needed)shinchiro.mpv
yt-dlpFinding the audio of YouTube Music songsyt-dlp.yt-dlp
DenoThe JavaScript runtime yt-dlp needs for YouTubeDenoLand.Deno

The last step of the first-start wizard installs them for you with winget, Windows’ package manager. Listen opens a console window of its own that runs winget install for the programs that are missing. mpv asks for administrator rights once. When winget is done, press Check again; Listen uses the programs after a restart.

If you skipped the wizard or something is still missing, Listen shows a Helper programs dialog when it starts, with Install with winget, Check again and Later. You can also install the programs yourself:

winget install shinchiro.mpv yt-dlp.yt-dlp DenoLand.Deno

To update them, for example when YouTube Music songs stop playing, open Settings → Advanced → Updates → Helper programs and press Update. Show opens the dialog with the current state of each program.

Tip: If winget is missing, the console window points you to “App Installer” in the Microsoft Store.

Fedora

Install the RPM with dnf:

sudo dnf install ./listen-<version>-1.fc44.x86_64.rpm

Pick the file that matches your Fedora release (the fc44 part). The RPM pulls in mpv, PipeWire’s pw-record (for the visualizer) and the graphics libraries Listen needs. It recommends yt-dlp and Node.js for YouTube Music, plus a few optional packages (for example udisks2 for CD ripping and cifs-utils). If your setup skips recommended packages, install yt-dlp and nodejs (or Deno) yourself if you use YouTube Music.

The RPM installs the program under /usr, adds the menu entry and icon, and lets the built-in updater update it later (see Updates).

Other Linux distributions

Download listen-<version>-x86_64.tar.gz, unpack it and copy three files into your home folder:

tar xzf listen-<version>-x86_64.tar.gz
install -Dm755 listen-<version>-x86_64/listen ~/.local/bin/listen
install -Dm644 listen-<version>-x86_64/io.github.leks2205.Listen.desktop ~/.local/share/applications/io.github.leks2205.Listen.desktop
install -Dm644 listen-<version>-x86_64/io.github.leks2205.Listen.svg ~/.local/share/icons/hicolor/scalable/apps/io.github.leks2205.Listen.svg

Make sure ~/.local/bin is on your PATH. The archive also contains the licence files and the README.

Install these runtime dependencies with your package manager:

Needed forPackage (names vary by distribution)
Playback (required)mpv
Visualizerpw-record from PipeWire (pipewire-utils on Fedora)
YouTube Musicyt-dlp and a JavaScript runtime, either Deno or Node.js
Window systemWayland or X11 client libraries (EGL, xkbcommon, libX11, libxcb and friends); most desktops have them already
CD ripping (optional)whipper, flac, cdrdao (see CD ripping)

yt-dlp needs a JavaScript runtime to talk to YouTube. Listen finds Deno or Node in the usual places, including ~/.nvm and ~/.local/bin, even though desktop applications do not get your shell’s PATH.

A tarball install in ~/.local/bin can be updated by the built-in updater, which replaces the file in place (see Updates).

Try it without a server

To look around first, start Listen in demo mode:

listen --demo

Demo mode uses a small built-in library with placeholder artwork, so no server or account is needed. It does not save settings or credentials, and it does not check for updates. See Command line for the other options.

Building from source

If you prefer to build Listen yourself, see Building from source.

First start

The first time you start Listen, a short setup wizard offers the extras you may want. This page walks through its steps and what happens afterwards.

The wizard appears only on a fresh install: when no setup has been completed and no server is configured. Every step can be skipped and every choice can be changed later in Settings. The steps are listed on the left; click one to jump to it, or use Back and Next. Skip setup at the bottom left closes the wizard at any time.

1. Welcome

Choose the interface Language. The default, System default, follows your system language. The list has 17 languages; see Languages. The wizard switches language immediately.

2. Features

Tick what you want. Everything here is a normal setting that you can change later.

OptionWhat it does
Auto-DJKeeps the music going with similar songs when the queue runs out. See Play modes and Auto-DJ.
DJ transitionsMixes songs the DJs pick with beat-matched blends instead of a gap. See DJ transitions.
Analyse songsMeasures tempo, beats, key and energy of your server’s songs in the background, for the DJ transitions. See Song analysis.
Analyse YouTube Music songsFetches a temporary copy of each YouTube Music song to measure it, so those songs can be mixed too. Needs an analysis folder (next step).
AI DJPicks sets of songs and talks between them. Needs your own Gemini key, so the box is greyed out until you save one in step 4.
Synced lyricsLooks up lyrics online when your server has none. See Lyrics.
Discord statusShows what you are listening to in your Discord profile. See Discord status.
Tray iconKeeps Listen in the system tray. See Tray, window and notifications.
Check for updatesLooks for a new version on GitHub when Listen starts. Nothing is installed without asking. See Updates.

3. Analysis folder

DJ transitions need each song’s tempo, beats and key. Listen measures them once and keeps the results. Press Choose folder… to store them in a folder of your choice. If you pick a synced folder (Nextcloud, Syncthing and so on), your other computers reuse the results instead of measuring again.

Without a folder, results stay in Listen’s own data folder and YouTube Music songs are not analysed. Analyse YouTube Music songs is off by default and can only be switched on once a folder is chosen; Listen then fetches a temporary copy of each YouTube Music song it is about to mix and keeps only the measurements.

4. AI DJ

This step takes your Gemini API key for the AI DJ. You can skip it. The wizard shows the three steps to create a key (open Google AI Studio, click Create API key, copy the key that starts with AIza), a button Open Google AI Studio, a field for the key and Save key. After saving, tick Turn on the AI DJ.

The full walkthrough, including what is sent to Google, is in Creating a Gemini API key and AI DJ. In short: requests go from your computer straight to Google, and the key is kept in your system keyring. Outside the EU, UK and Switzerland, Google may use free-tier requests to improve its products.

5. Helper programs (Windows only)

On Windows the last step installs mpv, yt-dlp and Deno with winget. See Installation. On Linux the wizard has four steps and ends at the AI DJ.

Connect your music

On the last step the Next button reads Connect your music. It closes the wizard and opens the sign-in page, where you add your first source. Continue with Connecting your music.

If you cancel out of the wizard with Skip setup, the same sign-in page appears. The wizard is not shown again once it is finished, or once a server exists.

Connecting your music

This page explains how to add a Navidrome or OpenSubsonic server, a Jellyfin server and local folders, and how to manage several servers. YouTube Music has its own page: YouTube Music.

Open the sign-in page

On a fresh install the sign-in page appears after the first-start wizard. Later, open it with Add server in the sidebar’s server list, in the app menu, or in Settings → General → Servers.

The page has four tabs: Navidrome, Jellyfin, YouTube Music and Local. Below the form it lists Your servers, so a broken entry can be edited or removed from here too. If you already have a server, a Cancel button takes you back.

Passwords are stored in your system keyring (Secret Service on Linux, Credential Manager on Windows). If there is no keyring, they go in a credentials file in Listen’s config folder that only your user can read. You can choose with Settings → General → Servers → Password storage: System keyring or File only.

Any server that speaks the OpenSubsonic (Subsonic) API works: Navidrome, Gonic, Airsonic and similar.

  1. Choose the Navidrome tab.
  2. Enter the Server URL, for example https://music.example.com, your Username and Password.
  3. Press Connect.

Two switches adjust how Listen talks to the server:

OptionWhat it does
Legacy authenticationSends the password (hex-encoded) instead of a token and salt. Only for old servers that need it.
Ignore certificate errorsAccepts an invalid or self-signed certificate from this server only. The server’s identity is then not checked, so someone on your network could read your password. Use it only for a server you run yourself.

Jellyfin

  1. Choose the Jellyfin tab.
  2. Enter the Server URL, for example https://jellyfin.example.com, plus Username and Password, and press Connect.

Only the server’s music libraries are used.

Discovery. When you open the sign-in page (on a fresh install, or with Add server), Listen looks for Jellyfin servers on your local network and lists them under Found on your network. Press Use to fill in the address. Press Scan again to search again. Servers you already added are not listed.

Quick Connect. Instead of typing a password, press Sign in with Quick Connect. Listen asks the server for a code. On a device where you are already signed in to Jellyfin, open Quick Connect and enter the code, or press Open the approval page. Listen waits for the approval and signs in. Cancel Quick Connect stops waiting.

Jellyfin has two extra switches:

OptionWhat it does
Prefer instant mixBuilds radio from Jellyfin’s instant mix instead of asking for similar songs first.
Ignore certificate errorsAs above.

Local folders

  1. Choose the Local tab.
  2. Type a path such as ~/Music, or press Browse… and pick the folder.
  3. Press Connect.

Listen reads the tags and cover art of the files in the folder and its subfolders (MP3, FLAC, Ogg, Opus, M4A, WAV and more). Large folders take a moment to scan. You can add more than one folder; each becomes its own entry in the server list.

After you add files, press Rescan next to the folder in Settings → General → Servers.

Several servers side by side

Every source you add appears in the sidebar’s server list at the top, with its type underneath. Servers that are not connected yet show “not connected”.

  • Switch: click a server in the sidebar, choose it in the app menu, or press Switch in Settings → General → Servers (the current one shows Browsing). Library pages show the active server.
  • One queue: the queue can hold songs from different servers. Switching the browsing server does not clear it.
  • Edit: press Edit next to a server in Settings → General → Servers to open the Edit server dialog.
  • Remove: click the cross next to a server (Remove server), then confirm with Yes. In Settings the button reads Remove. This only removes the entry and its saved password from Listen, not anything on the server.

Editing a server

The Edit server dialog shows the Name and, depending on the source:

  • Navidrome and Jellyfin: Server URL, Username, Password (leave it empty to keep the saved one) and the option switches above. Saving checks the connection first (the button reads Checking…).
  • Navidrome only: Server music folder (optional) and Local music folder. If your server’s music folder is mounted on this computer (for example /music on the server and /mnt/nas/Music here), fill in both so that Show in file manager works for those songs. Leave them empty to hide that action.
  • Local: Music folder.
  • YouTube Music: change the channel, switch browser or Reconnect (read the cookies again). See YouTube Music.

When a server needs attention

If the server you are browsing cannot be used when Listen starts or when you switch to it, Listen shows a page with the reason instead of an empty library.

Page titleMeaningButtons
Sign in to <name> againListen has no saved password for this server, or the server no longer accepts it.Enter the password (opens the edit dialog), Try again
Could not reach <name>The server did not answer; the reason is shown.Try again, Edit server

Both pages also offer Add a server, a list of Your other servers with Use and remove buttons, and a way to remove the failing server. If you have downloaded songs, Play downloaded songs (offline) opens them without a server. See Downloads.

Next steps

YouTube Music

This page explains how to connect YouTube Music to Listen, what works, and what to do when sign-in fails.

Note: YouTube Music support is unofficial. Listen is not affiliated with or endorsed by Google or YouTube. It uses YouTube Music’s web interface and the separately installed program yt-dlp, may stop working whenever YouTube changes something, and may not be allowed by YouTube’s Terms of Service. You use it with your own account and at your own risk; YouTube may restrict accounts it considers to be accessed by unofficial clients. A YouTube Music Premium subscription is recommended.

How sign-in works

YouTube Music does not let third-party apps sign in with Google directly. Instead, Listen uses the YouTube session of a browser you already use on the same computer. You never type your Google password into Listen.

Listen stores only which browser profile and which channel to use. The cookies themselves are read again from the browser at every start and, while Listen runs, whenever YouTube has rotated its session cookie — an old one is answered as signed out, which used to empty the library and the playlists until the next restart. They stay on your computer and are sent only to YouTube. This means Listen stays signed in for as long as the browser does.

Supported browsers: Firefox, Chrome, Chromium, Brave, Edge, Vivaldi and Ecosia, plus the Flatpak versions of Firefox, Chrome, Chromium, Brave and Ecosia.

Sign in with a browser

  1. Sign in to music.youtube.com in one of the browsers above.
  2. In Listen, open Add server and choose the YouTube Music tab. Listen looks for a signed-in browser and shows a button such as Sign in with Firefox.
  3. Press it. If your Google account has more than one YouTube channel (a personal one and one or more brand channels), Listen asks Which <browser> channel has your music? and lists the channels. Pick the one that holds your music library.
  4. Listen connects and opens your library.

If the library looks empty, you probably picked the wrong channel. Open Edit on the server (see below) and choose another one.

Use another browser

If several browsers are signed in, possibly with different Google accounts, press Use another browser. Each entry shows its state, for example “signed in to YouTube”, or the reason it cannot be used. If a browser has several profiles, the profile folder name is shown in brackets. If no browser is found, the page shows why and a Look again button.

The browser is open

Chromium-based browsers keep their cookie file locked while they run. If Listen reports that the browser keeps its cookies locked, close the browser completely (including background processes and tray icons) and try again.

Windows: Chrome, Edge and Brave

Recent versions of Chrome, Edge and Brave on Windows encrypt their cookies in a way that only the browser itself can read (“app-bound” encryption). Listen then shows a message to that effect. You have two options:

  • Sign in with Firefox, which stores its cookies unencrypted. This is the simplest way.
  • Use a cookies file (next section).

Cookies file

  1. In a browser where you are signed in to music.youtube.com, export the site’s cookies with an extension such as Get cookies.txt LOCALLY. JSON and cookies.txt formats work; a Cookie-Editor JSON export and a raw Cookie header work too.
  2. In Listen, open Add server, choose YouTube Music and press Other ways to connect (cookies file, guest).
  3. Press Browse… and pick the file, drop the file onto the window, or paste the cookies into the field below.
  4. Press Connect with cookies / as guest.

Listen keeps only the cookies a browser would send to music.youtube.com and needs the SAPISID cookie among them. A cookies file stops working when you sign out of YouTube in the browser it came from.

Guest mode

In the same Other ways to connect section, leave the file and the paste field empty and press Connect with cookies / as guest. As a guest you can search, open albums and artists, start radio and play songs. You have no personal library, likes, playlists or history.

What works

When you are signed in:

  • Your library: liked songs, saved albums, artists, and playlists, including creating, editing and reordering them. An Uploads list appears if you have uploaded music.
  • A home feed of quick picks, mixes and albums.
  • Search, album and artist pages, radio and Auto-DJ based on YouTube’s “play next” lists, and lyrics.
  • Music videos for YouTube Music songs, with the song/video switch in the player bar. See Music videos.
  • Playing a song reports it to YouTube Music, so your history and recommendations stay current there.
  • Mixing YouTube Music songs with DJ transitions, once you switch on Analyse YouTube Music songs and choose an analysis folder. See Song analysis.

Your own copy of a song

When a YouTube Music song is also on one of your own servers (Navidrome, Jellyfin or a local folder), Listen plays that copy, which usually sounds better. It looks the song up by title and artist when the song enters the queue, ignores things like “(Official Video)”, “(Remastered 2011)” or “- Topic”, compares the length, and never swaps a live, remix, instrumental or karaoke version for a different one. If nothing is found, or the server does not answer in time, the YouTube Music version plays.

The song stays a YouTube Music song: likes, playlists, radio and the music video work as before, and the play is reported to YouTube Music and also to the server that played it. A small server icon next to the title shows the swap; hover it to see the server, and press it to play the YouTube Music version instead (and again to go back). The video switch keeps working: the video runs silently alongside the server’s audio.

Turn it off with Settings > Playback > Prefer my own servers for YouTube Music songs. See Music videos for how the picture is lined up.

Audio is streamed, not saved. Listen does not download YouTube Music songs for offline use, and the offline download feature works only for your own servers.

Requirements

yt-dlp finds the audio stream of each song. It is a separate program, and it needs a JavaScript runtime (Deno or Node.js). On Windows the first-start wizard installs both; on Linux install them with your package manager (see Installation).

Managing the connection

Open Settings → General → Servers and press Edit next to the YouTube Music entry. The dialog offers:

  • Change channel… to list your channels and pick another one.
  • Use <browser> instead to switch to a different signed-in browser.
  • Reconnect (read the cookies again) after you signed in again in the browser.

When something stops working

YouTube changes things often.

  • Songs do not play, or play only some of the time. Update yt-dlp first. On Fedora: sudo dnf upgrade yt-dlp. On Windows: Settings → Advanced → Updates → Helper programs → Update.
  • The library is empty or errors appear. Listen reads the browser cookies again by itself when YouTube reports it as signed out, so this normally clears up without a restart. If the library still stays empty, press Reconnect in the edit dialog, then check the channel. If it still fails, a new Listen version may be needed; see Updates.
  • Sign-in fails after you changed your Google password or signed out in the browser. Sign in to music.youtube.com in the browser again, then reconnect.
  • Windows security warnings. Some antivirus programs find reading a browser’s YouTube sign-in unusual. Listen reads only the cookies of youtube.com and music.youtube.com.

You can also run listen --check-youtube-music in a terminal to see what Listen can see (channels, counts and whether playlists and albums open) without starting the interface. It never prints cookies. See Troubleshooting.

Updates

This page explains how Listen finds and installs new versions, and how to control it. Updates come from the project’s public GitHub releases; no account or token is needed.

How it works

When Listen starts, it asks GitHub for the list of releases (if Check on start is on). If there is a newer version for your release channel, an Update available dialog opens. It shows the new version, the release notes and what installing will do. Nothing is installed without your confirmation.

When you press Download and install, Listen downloads the package for your system together with the release’s SHA256SUMS file and checks the package against it. If the checksum does not match, nothing is installed. A release without a SHA256SUMS file cannot be installed by the updater.

What happens next depends on how you installed Listen:

InstallationWhat the updater does
Fedora RPM (program under /usr)Installs the matching RPM for your Fedora release with pkexec dnf install. You are asked for your password.
Tarball or other copy under your home folder, such as ~/.local/bin/listenReplaces that file in place. Listen first checks that the new program reports the expected version.
Windows installerRuns the new Listen-Setup-<version>.exe silently in the background, closes Listen and starts the new version. Your queue and window position are saved first.

After an RPM or tarball update the dialog says “Installed. Restart Listen to use the new version.” Press Restart now, or Later.

If Listen cannot update itself, the dialog explains why instead. This happens for a development build, for a Windows copy that was not set up by the installer (download the new installer from the release page), and for a program installed somewhere else, such as a package from another distribution (update it with the tool you installed it with).

The choices in the dialog

ButtonEffect
Download and installInstalls as described above.
Remind laterHides the dialog for 24 hours.
Skip this versionNever opens the dialog automatically for this version. A newer version is offered again.

Skipping and reminding only affect the automatic dialog at start. You can always open the update yourself in the settings.

Settings

Everything is in Settings → Advanced → Updates.

SettingDescriptionDefault
Check for updatesCheck now looks immediately and shows the result.
Check on startLook for a new version when Listen starts.On
Release channelStable offers full releases only. Beta also offers pre-releases.Stable
Update availableAppears when a newer version was found; View update opens the dialog, even for a skipped version.
Helper programsWindows only: Show and Update for mpv, yt-dlp and Deno. See Installation.
Release sourceOpen releases opens the GitHub releases page.

The first-start wizard has the same switch as Check for updates.

Notes

  • A manual Check now always opens the dialog when an update exists, even if you skipped it or asked to be reminded.
  • Updates are not checked in demo mode (listen --demo) or with --ephemeral.
  • Switching to Beta is safe to undo: switch back to Stable and you are offered full releases again, but Listen does not downgrade by itself.
  • Update checks are one of the few things Listen contacts without you adding a service. See Privacy and security. If you do not want them, switch Check on start off.

The window

This page describes how Listen’s main window is laid out: the sidebar, the title bar, the page area, the player bar and the side panels, and how the layout changes when the window gets narrow.

Overview

In the normal layout the window has these parts:

PartWhereWhat it is
Title barTop, 30 pxListen’s own window bar (optional, see Title bar)
SidebarLeftNavigation, servers, collections and playlists
PageMiddleThe page you are on: home, albums, a playlist, settings, …
Side panelRightQueue, lyrics and visualizer (optional)
Player barBottomPlayback controls, always visible

Listen remembers the window size, its position and whether it was maximized. On Wayland a program cannot place its own window, so only the size and the maximized state come back there. The window starts at 1600 x 950 px the first time, and it cannot be made smaller than 480 x 120 px. See Tray, window and notifications for tray behaviour, single-instance start and sleep prevention.

The sidebar

The expanded sidebar has an action bar at the top and a scrollable list below it.

Action bar

ControlWhat it does
Search boxOpens the command palette (Ctrl+K). It is a button, not a text field.
Collapse buttonFolds the sidebar into the narrow icon rail.
MenuOpens the app menu.
Back / Forward arrowsStep through the pages you visited, like a browser. They are grey when there is nothing to go back or forward to.

Sections

From top to bottom the list holds:

  1. Servers: every server you added, with its type and Add server. Click a server to browse it; playback of the current queue continues. A server that is not connected shows “not connected”. The small remove button next to a server asks for confirmation. This section is not shown in the demo library (listen --demo).
  2. My Library: the pages you chose (see Choosing and ordering the pages), followed by Downloads and, on Linux with a CD drive attached, Rip CD (see CD ripping).
  3. Collections: saved sort and filter combinations of the Albums and Tracks pages. The section only appears when you have saved one. See Collections.
  4. Playlists: your playlists, with a + button to create one.
  5. Shared Playlists: playlists other people made that you can see. Only shown when there are some.

Each of the last four sections has a header with a chevron; click it to fold or unfold the section. Listen forgets which sections you folded when it restarts.

Choosing and ordering the pages

Open Settings → General → Sidebar. Sidebar configuration lists every page. Tick a page to show it, and drag the grip on its left to move it.

PageShown by default
Now playingno
Searchno
Homeyes
Favoritesyes
Albumsyes
Tracksyes
Album artistsyes
Artistsyes
Genresyes
Foldersyes
Playlistsno (the playlists are listed in their own section)
Collectionsyes
Recently playedyes
Statisticsyes
Mixesyes
Radioyes
Settingsno (it is in the app menu)

A page that the current server cannot offer is hidden even when ticked. For example, YouTube Music has no Folders or Album artists, and only Navidrome and OpenSubsonic servers have Folders and Radio. Downloads is always shown.

Playlists in the sidebar

These rows are under Settings → General → Sidebar:

SettingMeaning
Sidebar playlist listShow or hide the playlist sections. On by default.
Playlist filter regexPlaylists whose name matches this regular expression (case-insensitive) are hidden. A pattern that is not valid hides nothing and shows a warning. Example: ^daily mix.*
Sidebar playlist sortingLets you drag playlists into your own order. Off by default; the server’s order is used. While it is on, a click on a playlist still opens it, but dragging moves it.
Sidebar playlist modeExpanded (cover, name and song count; the default) or Compact (name only).
Enable foldersTurns playlist names such as Workout/Run into folders. Off by default.
Folder separatorThe text that separates folder levels in a name. Default /.
Folder viewTree view (nested, collapsible folders; the default), Single folder (top-level folders only, each named by its whole path) or Navigation view (one level at a time with a back arrow).
Tree indentPixels each level is indented, 0 to 64, default 16. Tree view only.
Tree line colorColour of the connecting lines as #rrggbb. Empty uses the theme’s border colour. Tree view only.
Sidebar (collapsed) navigationShows the back and forward arrows in the collapsed rail. On by default.

With folders on, a header button expands or collapses all folders at once.

You can drop songs on one of your own playlists in the sidebar to add them; see Drag and drop.

Collections

A collection is a saved query: the sort, its direction, the search text and the filters of the Albums or Tracks page. To save one, set up the page the way you want it, click the bookmark button (Collections) in the page header, type a name under Save these filters as… and press Save.

In the sidebar, click a collection to open the matching page with that query applied. The three dots next to a collection offer Rename and Delete. See Lists, selection and menus for the controls themselves.

The collapsed rail

When you collapse the sidebar it becomes a rail 84 px wide. It shows:

  • optionally the back and forward arrows,
  • a Menu button that opens the app menu,
  • one icon with a small label for each page you enabled, plus Downloads, Rip CD (when a disc is present), Search and Settings, which the rail always shows,
  • a Collections button that opens a menu of your collections (only if you have some),
  • your playlists as small covers, under a Playlists heading. The chevron there hides or shows the covers and + creates a playlist.

You can collapse and expand the sidebar in three ways: the collapse button in the action bar, Collapse sidebar / Expand sidebar in the app menu, or by dragging the sidebar’s edge (see Resizing).

If you expanded the cover of the playing song into the sidebar (the arrow that appears on the cover in the player bar), the cover shows large at the bottom of the expanded sidebar, and floats next to the rail when it is collapsed. Click it to open the full-screen player. Settings → General → Player bar → Expand album art button turns this arrow off.

The app menu

The Menu button in the sidebar opens a small menu. Its entries are:

EntryWhat it does
Select server, your servers, Add server, Manage serversSwitch the server you browse, add one, or jump to Settings → General → Servers. Not shown in the demo library.
Open command paletteSame as Ctrl+K.
Go back, Go forwardOnly when the sidebar is collapsed and the layout is not compact.
Collapse sidebar / Expand sidebarNot shown in the compact layout.
Private modeNothing is scrobbled, shown on Discord or saved in the listening history until you turn it off or restart Listen. See History, statistics and mixes.
SettingsOpens the settings page.
Version x.y.zOpens the release notes in your browser.
QuitCloses Listen completely (even when “close to tray” is on).
Two layout buttonsPut the queue panel in a column on the right or in a panel under the page. Shown while the queue panel is on and the layout is not compact.

Title bar

By default Listen draws its own 30 px window bar. Choose its look in Settings → Window → Window bar style:

  • Windows: the app icon and the playing song on the left, minimize, maximize and close on the right. This is the default.
  • macOS: round red, yellow and green buttons on the left and the title centred.
  • Native: your desktop draws the frame and Listen shows no bar of its own.

You can drag the custom bar to move the window, double-click it to maximize or restore, and right-click it for the desktop’s window menu. With a custom bar the window can be resized by dragging any edge (5 px wide) or corner (10 px). Track info in window title (same section) controls whether the playing song is shown in the bar and in the window title. In private mode the title says so.

The page area

The page area shows whichever page you opened. Pages are described in Library pages.

Right-hand panels

The queue panel on the right (or under the page) can show three panels: the queue, the lyrics of the playing song and a visualizer strip. Open Settings → Playback → Player sidebar panels:

SettingMeaning
Queue panelShow the play queue in the right sidebar.
Lyrics panelShow the lyrics of the playing song.
Visualizer panelShow a spectrum strip. It only captures Listen’s own audio.
Combine lyrics and visualizerPut both in one panel, with the visualizer under the lyrics.
Panel orderThe order of the panels from top to bottom.

Two settings in Settings → Playback → Queue change how the whole panel sits in the window:

  • Side play queue style: Attached (a panel next to the page) or Detached (a drawer that slides in when you rest the pointer on the right edge).
  • Side queue layout: Horizontal (a column on the right) or Vertical (a panel under the page).

The panel is hidden on the Now Playing page, because that page shows the queue itself, and in the full-screen player. The queue is described in Player bar and queue.

Resizing

Drag the thin divider to resize:

DividerRange
Between sidebar and pageThe sidebar is 260 to 400 px wide. Drag it further left, below 160 px, and it folds into the rail. Drag it back out and it opens again.
Between page and right panel300 to 900 px wide (600 px by default).
Above a panel under the page (vertical layout)The height of the panel.
Between two stacked panelsHow much room each panel gets.

Your sizes are saved.

Compact layout and the mini player

There is no separate mini-player window. Instead, Listen switches to a compact layout whenever the window is 768 px wide or narrower, so shrinking the window gives you a small player. There is no button for this; it follows the window width, and the layout switches back above 768 px.

In the compact layout:

  • The sidebar and the side panels are gone. The page fills the window above a 90 px player bar.
  • A floating Menu button at the bottom left of the page opens the sidebar as a 320 px drawer over the page. Click outside the drawer or press Esc to close it. The button is hidden when the window is less than 192 px high.
  • The player bar shows the cover, the title with a three-dots song menu, and previous, play and next. The speaker button opens a vertical volume slider.
  • The full-screen player switches to a phone-style layout with shuffle, repeat, queue, lyrics and video buttons.

At the smallest size, 480 x 120 px, little more than the player bar fits, which makes a compact strip for keeping music controls beside other windows.

The settings Player bar button size, the skip buttons and the volume options are in Settings → General → Player bar.

Where to go next

Library pages

This page describes the pages you reach from the sidebar: the home feed, albums, artists, tracks, genres, folders, favorites and the pages built from your listening history. The tables, grids and menus that appear on these pages work the same everywhere and are described in Lists, selection and menus.

What a page shows depends on the server you are browsing. Navidrome and OpenSubsonic servers offer everything. Jellyfin, YouTube Music and local folders have no folders page, and some have no genres or radio. A page the current server cannot provide is left out of the sidebar. The table at the end of this page lists the differences.

Home

The home page is a feed of carousels.

Featured carousel. At the top, a banner shows random albums from your library with a large cover, the album’s genres and year, and a Play button (the label follows your play button behavior). Use the round arrows at the sides to move on. With the pointer over the banner, Shift plus the mouse wheel also steps through it. In Settings → General → Home you can switch it off (Home featured carousel) or choose Home featured carousel style: Single (one album, the default) or Multiple (a row of two to six albums, depending on the window width).

The server’s own feed. YouTube Music has a home feed of its own, with shelves such as quick picks and mixes made for your account. Its shelves come first. The other sources have no feed of their own.

New from your artists. With YouTube Music as the active server and your own listen-server set up (Merge with other devices in Settings → Advanced → Listening history), the first shelf shows the albums and singles that came out from the artists you follow on YouTube Music and the 50 artists you played most in the last year. The server reads their artist pages once a day with the YouTube Music session the phone shared, at most 200 requests a day, and lists a release from the day it first saw it for 60 days. The first time it reads an artist, only releases from this year count. A deluxe edition, repackage, remix release or other version of a release that is already known is not shown again. Click a card to open the album. The shelf needs listen-server 0.7.0 or newer; switch it off with New from your artists in Settings → General → Home.

Sections. Below that come the sections, in this default order:

SectionContent
GenresColoured genre tiles, each with a play button. View more opens the genres page.
Most PlayedYour most played albums (songs on Jellyfin).
Explore from your libraryRandom albums.
Newly added releasesAlbums most recently added to the server.
Recently playedAlbums you played most recently.
Recently releasedAlbums by release year, newest first.
PlaylistsYour playlists.

Each carousel shows as many cards as fit the window. Use the arrow buttons in its header, drag the row sideways, or hold Shift and use the mouse wheel to move along it. Listen loads 20 more cards when you get near the end. The refresh button in a section’s header loads it again.

To choose which sections appear and in what order, open Settings → General → Home → Home sections. Tick a section to show it and use the up and down arrows to move it.

If the page says “Your library looks empty.”, the server returned nothing for any section.

Albums

Albums lists every album on the server. It starts as a grid of covers and loads more as you scroll.

The header holds the page title and the number of albums (shown as “250+ albums” while more are still loading), a Play button and a Shuffle play button that play everything the current search and filters match (up to 20,000 songs), and these controls:

  • Sort by and a button for ascending or descending order. The options depend on the server. Navidrome offers, for example, Album artist, Artist, Duration, Most played, Name, Random, Rating, Recently added, Recently played, Song count, Favorited and Release year.
  • Filters, the funnel button, with filters such as Favorited, Rated, Compilation, Recently played, Artists, Genres, Year and custom tags. Which ones exist depends on the server.
  • Refresh.
  • Collections, the bookmark button, to apply or save a query.
  • A Search box.
  • The buttons for table, grid and detail view and the list options. See Displays.

Listen remembers the sort, order and filters of the Albums and Tracks pages between sessions.

Album page

Click an album anywhere to open its page.

The header shows the cover, the release type (Album, EP, Single, Compilation, …) and the version if there is one, the title, a line with release date, number of tracks, running time, an “Explicit” mark, size on disk and play count, and the album artists as links to their pages.

Below that are the buttons:

  • Play (or Add next / Add last, following your play button behavior), then Add next and Add last. The chevron next to them opens Shuffle, Add next shuffled and Add last shuffled. Holding the main Play button for half a second plays the shuffled version.
  • Start radio, if the server can find similar songs.
  • Five stars to rate the album (Navidrome and OpenSubsonic servers).
  • A heart to add the album to your favorites. On YouTube Music this saves the album to your library.
  • More options, the three dots, which opens the album’s context menu.

A toolbar has a Search box that filters the tracks, a sort menu for the tracks (the album’s own order by default, or title, artist, duration, play count, rating, year and more), an order button and the list options. When an album has several discs and you are not searching or sorting, the tracks are grouped under Disc 1, Disc 2 and so on, with the disc title when the server knows it. Tick a disc header to select all its tracks.

A long album comment is shown under the toolbar and can be expanded with Show more.

At the bottom of the page you find, where the data exists:

  • the genres, as links to the genre pages,
  • tags (release type, release country and status, Explicit), the record label, moods and groupings,
  • External links, see External links,
  • a copyright line with the label,
  • More from carousels: one for the first album artist and one each for up to two of the album’s genres. The genre carousels have a refresh button that picks other random albums.

Artists and album artists

Listen separates two lists, as Navidrome and Feishin do:

  • Album Artists: artists that appear as the album artist of at least one album. This is usually the list you want. YouTube Music has no album artists.
  • Artists: everyone credited on a track, including guests and composers. On YouTube Music this page shows the artists you subscribe to.

Both pages are grids of portraits by default, with the number of albums and songs. They have no sort or search box; use the command palette to find an artist by name. Click an artist to open the page.

Artist page

The header shows the portrait, ARTIST, the name and a line such as “4 albums, 52 tracks, 3 hr 20 min”. The buttons are Play, Shuffle, Add next, Add last, a radio button (when the server supports it), a heart, five stars (Navidrome only) and three dots, which reveal Refresh and Copy name.

Below the header there are shortcuts: VIEW DISCOGRAPHY, VIEW ALL TRACKS and ARTIST RADIO; the artist’s genres as buttons; and EXTERNAL LINKS. Then the sections follow in the order you chose:

SectionContent
About … (Biography)The server’s biography, collapsed to a few lines with Show more.
Recent releases (discography)The artist’s albums grouped by release type, such as Album, EP, Single, Live and Compilation. Choose how to sort (Release date, Name, Song count, Duration, Play count, Rating), reverse the order, search, and under the sliders button choose Group by Primary types or All types. Each group has play buttons; a group shows 100 cards, then View more.
VideosYouTube Music only: the artist’s music videos.
Related artistsSimilar artists, with arrows.
Top songsTen songs with a search box and play buttons. Community shows the server’s list; Personal ranks the artist’s songs by how often you played them, from your listening history. The page says “Nothing played yet.” when there are none. View all lists all of them.
Favorite songsTen songs you favorited. On servers with ratings you can switch between Favorite and Rating. View all lists all.

In Settings → General two sections control the page:

  • Artist page: Artist page configuration (tick sections and reorder them), Artist release type configuration (which release types to show and in which order the groups appear) and Artist radio count (how many songs an artist radio queues; 20 by default).
  • External links: see below.

Artist pages and album pages can show small buttons that open other websites in your browser. In Settings → General → External links you can switch the whole feature off (External links) or choose each site:

SiteWhere it leads
Last.fmThe artist or album on Last.fm. If the server supplied a Last.fm address, that one is used, otherwise a search by name.
MusicBrainzThe artist or album on MusicBrainz. Only shown where the server knows the MusicBrainz id.
ListenBrainzThe artist (by MusicBrainz id when known, otherwise a search) or a search for the album.
QobuzA search for the artist or album on Qobuz.
SpotifyA search on Spotify’s web player. With Open in the Spotify app on, the link opens the desktop app instead.

Listen only builds the address. Nothing is sent to these sites until you click a button.

Tracks

Tracks lists every song on the server as a table. Like the Albums page it has Play, Shuffle play, sort, filters, refresh, collections and search, and it loads more rows as you scroll. The default columns are the number, a cover with title and artist, duration, album, genre, year and a heart. You can change them in the list options (see Columns).

Genres

Genres lists the genres with their album and song counts. It has a Search genres box, a sort menu (Name, Album count, Song count) and an order button. Click a genre to open it.

A genre page shows either the albums or the tracks of that genre. Switch with the Albums and Tracks buttons; the choice is remembered. Both lists have the same sort, filter and search controls as the Albums and Tracks pages, without the genre filter.

Folders

Servers that organise music in folders (Navidrome and OpenSubsonic) have a Folders page. The left side is a tree: All folders at the top, and folders that open with a chevron and load their sub-folders on demand. The right side shows a trail of the folders you are in, the sub-folders as a strip with a play button each, and the tracks directly in the open folder as a list. The buttons above the list are Play, Play next, Play last, Shuffle and Refresh. A right-click on a folder opens a menu that plays or queues everything inside it, including sub-folders, or adds it to a playlist.

For folders on your own computer, see Connecting your music; a local folder source does not have a folder browser.

Favorites

Favorites collects what you marked with a heart. On servers that can favorite albums and artists it has three tabs: Tracks, Albums and Artists. On YouTube Music the tabs are named Liked Music, Saved albums and Subscriptions. A Play button plays the tab’s songs. If nothing has a heart yet the page says “No favorites yet.” (or “Nothing liked yet.” on YouTube Music).

Show or hide hearts everywhere with Settings → General → Lists → Show favourites.

Other pages

PageWhat it is
Now playingThe queue as a full page. See Player bar and queue. Hidden in the sidebar by default.
SearchThe search page. See Search and the command palette. Hidden in the sidebar by default.
PlaylistsAll your playlists. See Playlists and smart playlists.
Recently playedThe last 500 songs you listened to, newest first. Right-click a row and choose Remove from history to forget one play. Empty when the history is switched off.
StatisticsTop songs, artists and albums by year or of all time.
MixesPlaylists made from your listening history.
RadioInternet radio stations. See Internet radio.
DownloadsSongs stored for offline play. See Downloads.
SettingsSee Settings.

Recently played, Statistics and Mixes are described in History, statistics and mixes.

What each source offers

Page or featureNavidrome / OpenSubsonicJellyfinYouTube MusicLocal folder
Home sections and featured carouselyesyesyesyes
The server’s own home shelvesnonoyesno
Albums, Tracks, Artistsyesyesyour library (empty as a guest)yes
Album artistsyesyesnoyes
Genresyesyesnoyes
Foldersyesnonono
Favorites (songs)yesyesyes (Liked Music)no
Favorites (albums, artists)yesyesyesno
Star ratingsyesnonono
Radio stationsyesnonono
Offline downloadsyesnonono

YouTube Music support is unofficial. See YouTube Music for what that means and how to sign in.

Lists, selection and menus

Almost every page in Listen shows a list of songs, albums, artists, playlists or genres. They all share the same component, so they all look and behave the same way. This page explains the displays, columns, sorting and filters, how selection works, what the keyboard and mouse do, drag and drop, and the right-click menus.

Displays

A list can be shown in up to three ways. When a list offers more than one, two or three small buttons appear in its page header (Table view, Grid view, Detail view).

DisplayWhat it looks likeAvailable for
TableOne row per item with columnsAll lists
GridCards with a cover and a few lines of textAlbums, artists, playlists
DetailEvery album as a block with its cover, facts and track listAlbums

Song lists, genres, the queue and search results for tracks are always tables.

By default the Albums, Artists, Album Artists and Playlists pages start as a grid. Every other list starts as a table.

The look of a list (display, columns, sizes) is saved per kind of list, so all playlists share one look, all album grids share one look, and so on. The tracks of an album, the songs of a playlist, the queue panel and the Now Playing page each have their own.

List options

The sliders button in a page header opens List options. What it contains depends on the display.

Display switches between table, grid and detail (when more than one is offered).

Table options

OptionMeaning
Row sizeCompact (40 px), Default (64 px) or Large (88 px) rows.
Show headerThe row of column titles.
Highlight the row under the pointerOn by default.
Alternate row colorsZebra stripes.
Horizontal borders, Vertical bordersLines between rows and columns.
Fit columns to the widthOn by default: the columns stretch to fill the width. When off, they keep their width and the table scrolls sideways if needed.
ColumnsSee below.

Columns

Under Columns every column the list can show has a line with:

  • a checkbox to show or hide it,
  • up and down arrows to move it,
  • L and R to pin it to the left or right edge, so it stays in view when the table scrolls sideways,
  • an alignment button (left, centre, right),
  • Fit, which makes the column as wide as its longest value.

You can also work directly in the table header: drag a column title onto another to reorder, and drag the right edge of a title to change the width.

The columns available for songs are: album group, number (#), image, title (three variants: name only, title and artist, or cover with title and artist), duration, album, album artist, artist, composer, date, genre, genre badges, year, release year, release date, disc, track, bit depth, bitrate, codec, sample rate, last played, comment, channels, BPM, date added, path, plays, size, favorite, rating and actions. Albums, artists, playlists and genres have shorter sets (for example, albums offer song count, release type and last played; playlists offer owner and duration). A column that no source can fill is not offered, and a column the server has no data for stays empty.

The default song table shows the number, cover with title and artist, duration, album, genre, year and a heart. The songs of an album show track number, title, duration and heart in compact rows.

The Album group column groups the rows of a song table by album under a header with the cover, facts, a favorite heart and a rating. When you enable it, an Album group section appears in the options: the cover size (No cover, 64 to 160 px), which facts to show (album artists, release date, release year, song count, duration, release type, genres, size), Favorite and rating and Cover above the facts.

Grid options

OptionMeaning
Card sizeCompact (cover only, with the name on a strip at its bottom), Default or Large (fewer, bigger cards).
GapSpace between cards, from xs (10 px) to xl (32 px). sm (12 px) is the default.
Cards per rowTick it to fix the number of cards per row (1 to 20). Otherwise the number follows the window width.
Lines under a cardWhich lines to show under each cover and in which order, with an alignment button each. For albums the default is name, album artist and release year.

Hovering a card shows round buttons on the cover: play, Play next, Play last, the heart, More options and, for albums, a chevron that expands the album’s track list in a panel under the row.

Loading

Infinite scroll (the default) loads more rows as you scroll. Pages shows a fixed number of rows and a bar at the bottom (“1-100 of 1250”, Previous page, “Page 1 of 13”, Next page). Items per page is 100 by default and changes in steps of 25.

Reset to defaults puts the list back as it was.

Sorting, searching and filtering

The Albums page, the Tracks page and the albums and tracks of a genre have a header with these controls:

  • Sort by opens a menu of sort fields. The fields depend on the server: Navidrome offers the most, plain Subsonic servers and local folders offer a few. Tracks can be sorted by album, album artist, artist, BPM, duration, favorited, genre, name, play count, rating, recently added, recently played, release year and more.
  • The arrow button toggles ascending and descending order. Each sort field starts in its natural direction (for instance, “Most played” starts descending).
  • Filters opens Album filters or Track filters. See below.
  • Refresh loads the list again.
  • Collections (Albums and Tracks pages) lists your saved queries and lets you save the current one.
  • Search filters by text after you stop typing for a moment (about 0.4 seconds). The cross button clears it.
  • Play and Shuffle play play everything the current sort, search and filters match, up to 20,000 songs. Hold Play for half a second to play it shuffled.

Other lists (artists, genres, playlists, search results) have their own simpler controls, described on their pages. In table views the column titles do not sort; use Sort by.

Filters

The filter window offers the filters the server supports, so you may not see all of these:

FilterMeaning
FavoritedAny, Yes or No.
RatedAny, Yes or No.
CompilationAlbums only.
Recently playedAlbums only.
ArtistsPick one or, with Multiple, several artists.
GenresPick one or, with Multiple, several genres.
YearA single year or a From and To range.
TagsThe server’s custom tags, with a list of values to pick from.

On plain Subsonic servers only one of Favorited, Artists, Genres and Year can be used at a time; the others show “Off while another of these filters is on”. Reset clears all filters, Done closes the window. The filter button lights up while a filter is active.

Listen remembers the sort, order, search and filters of the Albums and Tracks pages and of genre pages between sessions.

Collections

To save the current sort, order, search and filters as a collection, click Collections, type a name in Save these filters as… and press Save. A saved collection appears in the same menu and in the sidebar. Click it to apply it. The bin button in the menu deletes it; in the sidebar the three dots offer Rename and Delete.

Selection and clicking

Listen’s selection rules differ a little from Feishin’s, so they are worth knowing.

ActionResult
Click on a row or cardOpens the item. A song opens its album; an album, artist, playlist or genre opens its own page. The click waits about a third of a second so that a double-click is not mistaken for it. A click also clears the selection.
Double-clickSongs play. Albums, artists, playlists and genres open.
Ctrl+clickAdds or removes one item from the selection.
Shift+clickSelects the range from the last item you selected to this one.
Right-clickOpens the context menu. If the item is not selected, it becomes the only selected item first.
Click the play button in the # columnPlays that row.

When something is selected, a bar at the bottom of the list shows “3 selected” with Clear and More. More opens the context menu for the whole selection.

A double-click on a song plays it and, with the default Play button behavior of Play now, queues up to 50 songs before and after it from the same list, so playback continues through the list. The queue panel itself behaves differently: a double-click there jumps to that song without replacing the queue.

In a grid the same rules apply to the whole card. If you turn off Settings → General → Lists → Grid multi-select, a click on the cover opens the item immediately.

Play button behavior

Settings → General → Lists → Play button behavior decides what the main Play buttons, a double-click on a song and the list’s play key do:

ChoiceEffectButton label
Play nowReplaces the queue and starts playing.Play
Add to queue nextAdds right after the playing song.Add next
Add to queue lastAdds to the end of the queue.Add last

Shuffle play, the Auto-DJ and the AI DJ do not depend on it. The other rows of the Lists section are Grid multi-select, Show favourites (hearts everywhere) and Show ratings (star ratings, for Navidrome and OpenSubsonic).

Keyboard

Keys act on the list you are looking at, when no text field has the focus.

KeyAction
Up, DownMove the selection one row.
Left, RightMove one card (grids only).
Home, EndFirst or last item.
Page Up, Page DownMove one screenful.
Ctrl+ASelect all, or deselect all if everything is selected.
EnterPlays the selection following Play button behavior.
Ctrl+GOpens the page of the first selected item (for example, the album).
Ctrl+LSelects and scrolls to the playing song, or opens its album.
SpacePlay or pause.

Enter, Ctrl+G and Ctrl+L are hotkeys you can change in Settings → Hotkeys; there are also optional hotkeys for List: play now, List: play next and List: play last. See Hotkeys. The context menu has its own keys: Up and Down move, Right opens a submenu, Left closes it, Enter runs the entry and Esc goes back or closes the menu.

Hover controls

Move the pointer over a row and its # column turns into a play button that follows the play button behavior. Rest on it for a moment and a small bar offers Play now, Play next and Play last. A right-click on the button opens the same three choices. The Actions column (three dots), when shown, opens the context menu. Hearts and stars in the Favorite and Rating columns work with one click; clicking the same star again clears the rating.

Drag and drop

Press on a row or card and move more than 6 px to start dragging. If the row is part of a selection, the whole selection is dragged. A small label follows the pointer. Drop it on:

  • the queue panel (or the Now Playing page): the items are inserted where you drop them. Dragging rows within the queue reorders them. Dropping on an empty queue starts playing.
  • one of your playlists in the sidebar: the items are added to that playlist. Playlists you cannot change do not accept drops, and neither does the sidebar while Sidebar playlist sorting is on (dragging then reorders the playlists).

Albums, artists and playlists that you drop are expanded into their songs first.

In a playlist’s edit mode, rows are dragged by a grip instead; see Playlists and smart playlists.

Context menus

Right-click any song, album, artist, playlist, genre or folder, or choose More options (three dots), to open its menu. The menu acts on the whole selection. Entries that the current server cannot do, or that do not apply, are left out. The footer of the menu previews what it acts on.

Songs

EntryWhat it does
Remove from historyOnly in Recently played: forgets those plays.
PlayA side menu with Play, Next, Last, Play (shuffled), Next (shuffled) and Last (shuffled). Clicking Play itself does what your play button behavior says.
Start radioPlays songs similar to this one. Greyed out for several songs.
Add to playlist…See Add to a playlist.
Remove from playlistOnly inside a playlist you can change. Asks for confirmation.
FavoriteAdd to favorites or Remove from favorites. On YouTube Music: Like and Remove from Liked Music. Not offered for local folders.
Set ratingNo stars to five stars. Navidrome and OpenSubsonic only.
Download / Remove downloadOffline copy. See Downloads.
Copy linkYouTube Music songs: copies the song’s public link.
Go toGo to album and Go to each artist. Greyed out for several songs.
Get infoSee below.
Edit metadata…Local folder songs only. See below.
Show in file managerLocal folder songs, one at a time.
Share…Servers that can create share links (Navidrome).
Save file…Servers that allow downloading the original file (Navidrome, OpenSubsonic and Jellyfin).
Clear selectionWhen opened from a list.

On rows of the play queue the menu starts with Remove from queue and has Move items (Move to top, Move to next, Move to bottom) and Shuffle (Shuffle selected, Shuffle all) as well. See Player bar and queue.

Albums

Play (side menu), Album radio (Play, Next, Last), Add to playlist…, Favorite (on YouTube Music: Save to library and Remove from library), Set rating, Download, Go to the album artists, Get info, Share… (on YouTube Music Copy link), Save file… and Clear selection.

Artists

Play (side menu), Artist radio, Add to playlist…, Favorite (on YouTube Music: Subscribe and Unsubscribe), Set rating, Get info, Share… or Copy link, Clear selection.

Playlists

Play, Shuffle, Play next, Add to queue, a Play side menu, Add to playlist… (adds all its songs to another playlist), Download, Open playlist, Edit playlist…, Edit smart rules… (smart playlists), Copy link (YouTube Music), Delete playlist…, Get info, Share…, Save file… and Clear selection. Editing and deleting only appear for playlists you own on a server that allows them. See Playlists and smart playlists.

Genres and folders

A genre has Play (side menu), Add to playlist… and Clear selection. A folder has the same, plus Share… and Save file… where the server allows it. A folder’s songs are collected recursively.

Get info

Get info opens a window with every fact Listen knows about the item. For a song that includes, where available, the id, title, artists, album, disc and track, year, genres, duration, codec, bitrate, sample rate, bit depth, channels, size, BPM, favorite, rating, play count, last played, dates added and modified, ReplayGain values, whether it has lyrics, the comment, MusicBrainz ids and the file path. Albums, artists and playlists show their own facts. Empty values are left out, and the server is asked for more details while the window is open. With several items selected, arrows step through them. A copy button next to a value copies it, a link button opens a MusicBrainz page, and the path of a local file has a Show in file manager button.

Edit metadata (local folders)

For songs from a local folder, Edit metadata… opens a tag editor. It edits Title, Artist, Album, Album artist, Track, Disc, Year, Genre, Comment and Lyrics, and the Cover: Use image (give the path of a PNG or JPEG file), Remove or Keep. You can select several songs; fields with different values show a hint and are left alone unless you type something. Preview changes lists exactly what will change, Write tags writes the files one by one, and Listen then rescans the folder. The files on disk are changed, so keep a backup if you care about the old tags.

On Navidrome, Share… opens Share item. Set Expiration with an amount and a unit, or use a preset (Server default, 1 day, 1 week, 1 month, 1 year), and optionally add a Description. Make default stores your choice as the default for new shares (you can also set it in Settings → General → Sharing). When you press Share, the link is created on the server and copied to the clipboard; the notification has an Open link button.

On YouTube Music, Copy link copies the public music.youtube.com address of the song, album, artist or playlist.

Save file

Save file… downloads the original, unconverted file from the server into your system Downloads folder (not Listen’s offline store). Several songs of one album go into a folder named after the album. If a file with that name exists, Listen adds a number such as “(2)”. A progress notification shows how far it is. Do not confuse it with Download, which stores a copy inside Listen for offline playback.

Search and the command palette

Listen has two ways to search: the command palette, a quick window you open from anywhere, and the search page, a full page with tabs. The palette can also jump to any page, switch servers and start a new playlist.

Both search the server you are currently browsing. With a local folder source they search that folder. If you want to search another server, switch to it first.

The command palette

Open the palette with Ctrl+K, with the Search box at the top of the sidebar, or with Open command palette in the app menu. Press Ctrl+K again to close it. You can change the shortcut under Settings → Hotkeys (the action is called Global search); see Hotkeys.

Start typing. After a short pause (about 0.4 seconds) Listen searches the server and shows up to five results per type under these headings:

HeadingChosen result does this
AlbumsOpens the album page.
ArtistsOpens the artist page.
TracksPlays the song right away.
PlaylistsOpens the playlist.

Each heading shows how many results it has. Click the heading to fold or unfold it. View all opens the search page on that tab with your text, so you can see more than five.

Under the results is a Search group with these commands, which you can also reach with an empty box:

  • Search for “your text” opens the search page with the same text.
  • Create playlist… opens the new playlist dialog. Only offered when the server can create playlists.
  • Go to page… opens a second page of the palette. The entries are Home, Search, Settings, Favorites, Recently played, Statistics, Mixes, Radio, Downloads under Pages, and Albums, Tracks, Album artists, Artists, Genres, Folders, Playlists under Library. Pages the current server does not have are left out. Typing narrows the list.
  • Server commands… lists your servers under Select server (choose one to switch to it) and Manage servers…, which opens Settings → General.

Keys

KeyAction
Up, DownMove the highlight.
EnterRun the highlighted entry.
EscGo back one page of the palette; on the first page it closes the palette.

The footer shows a breadcrumb of the pages you opened (click a part to go back) and the keys. The cross in the text box clears your text.

The search page

The search page is hidden in the sidebar by default. Show it with Settings → General → Sidebar (tick Search), or open it from the palette: Go to page… → Search, Search for “…” or View all.

Type in the box at the top. Listen searches while you type, after a short pause, and Enter searches at once. The results are in tabs:

  • Tracks,
  • Albums,
  • Artists,
  • Playlists, which appears when the server found some.

Once you have typed something, each tab shows its number of results, for example Albums (12). Listen asks the server for up to 100 results of each type. The box says “Type to search your library.” while it is empty, and the list says “No results.” when nothing matched.

Each tab is an ordinary list: you can switch between table and grid with the buttons at the right (albums and artists), change columns in the list options, select, drag and right-click exactly as described in Lists, selection and menus. Ctrl+F puts the cursor back into the search box (Local search in the hotkey list).

Describe it

With Merge with other devices set up (a listen-server address and token, see Continue on another device), the search page has a Describe it button next to the tabs. Turned on, the box takes a description instead of a title: “slow 90s Korean ballad”, “Brazilian samba with acoustic guitar”, “트로트”, “girl crush K-pop with heavy beats”, “dreamy lo-fi 80 bpm”. Press Enter to search (Listen does not search while you type in this mode). The results are songs only, best match first, up to 100.

Your listen-server ranks every song it has an embedding for by three things added together:

  • how the music sounds: a 30-second clip of each song, compared with your words by the CLaMP 3 music-and-text model,
  • what is known about the song: search tags (genre, decade, country, who sings, instruments, mood, scene names such as “city pop” or “1st-generation K-pop”) written once per song by Gemini from its artist and title, compared with your words by the same model,
  • the words themselves: words of your description found in those tags or in the title.

A tempo in the description (“120 bpm”) becomes a filter: only songs within 6 bpm of it (or at half or double speed) are shown, using the tempo from the analysis store.

The embeddings come from listen-embed, a job that runs on a computer with a graphics card (tools/listen-embed in the source, see its README) and writes to Listen/embeddings next to the analysis store. Songs it has not reached yet are not found by Describe it; the server lists them at /v1/search/missing and counts them in /v1/status. Results play from the server they belong to: YouTube Music songs on your YouTube Music account, Navidrome songs on the Navidrome server whose address matches; songs of servers you have not added are left out.

The first search after a while takes a few seconds longer while the server loads its text model; turning Describe it on starts that loading.

What gets searched

What the search matches depends on the server:

  • Navidrome, OpenSubsonic and Jellyfin search their library for song titles, albums, artists and, where supported, playlists.
  • YouTube Music searches YouTube Music’s catalogue, not only your own library. Results from it are played through the unofficial YouTube Music support described in YouTube Music.
  • Local folders search the files Listen found in the folder.

Filtering the lists on the Albums and Tracks pages is separate and works on your library only; see Sorting, searching and filtering.

Playlists and smart playlists

This page explains how to create, change and delete playlists, how to add songs to them, and how smart playlists work. Playlists live on your music server (or in your YouTube Music account); Listen does not keep playlists of its own.

What each source can do

ActionNavidrome / OpenSubsonicJellyfinYouTube MusicLocal folder
See playlistsyesyesyesno
Add songs to a playlistyesyesyesno
Create a playlistyesnoyes (signed in)no
Rename, change description and visibilityyesnoyesno
Remove songs, change the orderyesnoyesno
Delete a playlistyesnoyesno
Playlist coverNavidrome 0.61 and newernonono
Recommended songsyesyesyesno
Smart playlistsNavidrome onlynonono

Buttons for things a source cannot do are not shown. On YouTube Music you need to be signed in with an account; as a guest you can browse and play but not change playlists. A playlist you do not own, and YouTube Music’s built-in lists such as Liked Music, can be played but not edited. YouTube Music support is unofficial; see YouTube Music.

The Playlists page

The sidebar already lists your playlists, so the Playlists page is not in its list of pages by default. Show it by ticking Playlists in Settings → General → Sidebar, or open it from Go to page… in the command palette, or click the Playlists heading in the collapsed sidebar. The page shows your playlists as a grid or table. The header has:

  • the title and the number of playlists,
  • Play, which plays all listed playlists following your play button behavior,
  • a Search box (matches name, owner and description),
  • a sort menu with Name, Song count, Duration, Owner and Visibility, and an order button,
  • Refresh,
  • Create playlist and, on Navidrome, Create smart playlist,
  • the display buttons and list options described in Lists, selection and menus.

Creating a playlist

Any of these opens the Create playlist window:

  • the + button next to Playlists in the sidebar (or in the collapsed rail),
  • Create playlist on the Playlists page,
  • Create playlist… in the command palette,
  • Add to playlist… on a song, typing a name in New playlist… and pressing Create (this creates the playlist with the selected songs in it).

The window has a Name, and, when the server supports it, a Description and a Public checkbox. Press Create. Playlists start private unless you tick Public. On Navidrome a public playlist is visible to the other users of your server.

Opening a playlist

Click a playlist in the sidebar, in the Playlists page, in the home page or in the palette. The top of the page shows:

  • the cover,
  • the word PLAYLIST, a Public or Private badge and, for smart playlists, a SMART badge,
  • the owner, number of songs and total time,
  • Play (or Add next / Add last per your setting), Add next, Add last and a chevron with the shuffled variants, and More options, which opens the playlist’s menu,
  • the description, with Show more when it is long.

The toolbar below has:

ControlWhat it does
SearchFilters the songs by words in their title, artist, album or genre.
Tracks / AlbumsSwitches between the songs and the same songs grouped as album cards.
Sort menu and order buttonSorts the songs. The playlist’s own order is the default.
Filter buttonFilters by Favorites, Rating, Year (from and to), and by Genres, Artists and Album artists, each with Match All or Any.
RefreshLoads the playlist again.
Edit rulesSmart playlists you own: opens the rule editor.
EditStarts the order-editing mode (see below).
ChevronCollapses the large header so more rows fit.

Below the last song of a playlist, Listen offers five Recommended songs that should fit it: your server’s own similarity (Navidrome’s and OpenSubsonic’s getSimilarSongs2, Jellyfin’s Similar) seeded with the playlist’s first, last and middle song, or a YouTube Music radio around them. Songs the playlist already has are never offered, and the five are picked at random from everything that fits, so the strip changes as you open playlists.

  • a click on a recommended song plays it and the rest of the strip,
  • the + at its right adds it to this playlist in one click; the row disappears and a message confirms it,
  • the ↻ button next to Recommended asks for another five.

The strip is cached per playlist for ten minutes, so scrolling up and down or coming back to the page does not ask the server again; Refresh in the toolbar, or the ↻ button, asks again. Local folders have no server-side similarity, so they show no strip, and neither does an empty playlist.

Editing a playlist

Name, description, visibility and cover

Right-click the playlist (in the sidebar, the Playlists page or its own page) and choose Edit playlist…. Change the Name, Description or Public, and press Save. This is also how you rename a playlist. On YouTube Music the window reminds you that the current description and visibility are not shown; only the changes you make are sent.

If your Navidrome server can store playlist covers, small + and bin buttons appear over the cover of your own playlists. The + asks for an image file (PNG, JPEG, WebP or GIF, up to 10 MB). The bin removes the uploaded cover.

Changing the order

  1. Open the playlist and press Edit.
  2. Drag the rows by the grip in the first column to their new places. The row where you will drop it is outlined.
  3. Press Save and replace and confirm “Replace the playlist with the new order? Are you sure?”. Press Cancel to throw the changes away.

In edit mode, Order for smooth mixing puts the songs into an order that mixes well, the way the DJs order their picks (see Order for smooth mixing). The first song stays first. Check the result, drag anything you want elsewhere, and press Save and replace to keep it or Cancel to throw it away.

To just listen in that order without changing the playlist, right-click it and choose Play in smooth order.

While you edit, search, sort and filters are switched off and the page shows the songs as tracks. Save and replace writes the whole playlist back to the server, so avoid editing the same playlist elsewhere at the same time. Edit is only offered for playlists you own on servers that can reorder (Navidrome, OpenSubsonic and YouTube Music). If you press it before a long playlist has finished loading, Listen tells you to wait.

Removing songs

Select one or more songs in the open playlist, right-click and choose Remove from playlist. After you confirm (“Are you sure you want to remove this song from …?”) the songs are removed from the playlist on the server. The songs themselves stay in your library.

Deleting a playlist

Right-click the playlist and choose Delete playlist…. The menu then asks “Delete …? This can’t be undone.” Choose Delete to remove it or Cancel to keep it.

Adding songs to a playlist

There are three ways.

From a menu. Right-click songs, an album, an artist, a genre, another playlist or a folder, and choose Add to playlist…. The menu turns into a picker:

  • a Search playlists… box (it finds names even when you leave letters out),
  • New playlist… and Create, to make a new playlist with these songs (only on servers that can create playlists),
  • Skip duplicates, a tick box: songs already in the playlist are not added again. It is off by default, applies on Navidrome, OpenSubsonic and Jellyfin, and is not offered for YouTube Music.
  • the list of your playlists, with the one you used last pinned at the top and marked with a star.

Click a playlist to add the songs. A notification says what was added. Albums, artists and folders are added as all their songs.

By dragging. Select songs, drag them to one of your playlists in the sidebar and release. See Drag and drop.

On YouTube Music the picker shows a check mark behind playlists that already contain the song, and does not let you add it to them again. Songs always go into the playlist on their own server, so a queue that mixes servers can only add to a playlist of the song’s source.

Smart playlists

A smart playlist has no fixed list of songs. It stores rules, such as “genre contains rock and rating is greater than 3, sorted by play count, limited to 50”, and the server works out the songs. Smart playlists are a Navidrome feature, and Listen edits them through Navidrome’s own API. They appear in the sidebar like any other playlist, with a SMART badge on the playlist page.

Creating and editing

Press Create smart playlist on the Playlists page. To change an existing one, press Edit rules on its page or right-click and choose Edit smart rules…. The editor window has:

PartMeaning
Name, Description, PublicAs for normal playlists.
Refresh the songs when the playlist is openedThe server recomputes the list whenever you open the playlist.
Query editorThe rules, described below.
SortOne or more sort entries. Each has a field (or Random) and Ascending or Descending. Add sort adds another.
LimitAt most so many songs (#, empty means no limit) or so many percent of the matching songs (%, 0 to 100).

A rule group has a selector, Match all or Match any, and the buttons Add rule and Add rule group. Groups can be nested inside each other. The top group also has Reset to default and Clear filters; nested groups have Remove rule group.

A rule is a Field, an Operator and a value:

Field typeOperators
TextIs, Is not, Is missing, Is present, Contains, Does not contain, Starts with, Ends with
NumberIs, Is not, Is missing, Is present, Contains, Does not contain, Is greater than, Is less than, Is in the range (From and To)
Yes / noIs, Is not, Is missing, Is present
DateIs, Is not, Is missing, Is present, Is before, Is after, Is in the last and Is not in the last (a number of days), Is in the range, and the “(date)” forms that take dates as YYYY-MM-DD
PlaylistIs in, Is not in (pick another playlist)

The fields are the ones Navidrome knows, such as Name, Album, Artist, Album Artist, Genre, Year, Duration, BPM, Bitrate, Is Favorite, Rating, Play Count, Date Added, Date Last Played, File Path and many tag fields. If you use tags Navidrome indexes under other names, add them in Settings → General → Query builder → Custom fields: give each a Label, a type (string, number, boolean, date or playlist) and the Tag name used in rules. That section only exists while the server you browse supports smart playlists.

Press Create (or Save). The editor refuses an empty name, and shows the server’s message if the rules are not valid. Afterwards the playlist page opens and shows the songs the rules select.

Notes

  • Smart playlists are computed by the server. Listen only edits the rules and shows the result, so the same list also appears in other Navidrome apps.
  • The contents come from the rules, so change the rules rather than adding, removing or moving songs by hand.

History, statistics and mixes

Listen keeps a listening history on your computer. It feeds three pages: Recently played, Statistics (with a year review) and Mixes. This page explains what is recorded, how to control it, how to export or delete it, and what the pages show.

The history is never uploaded or shared. It is a plain text file on your computer, and everything on the three pages is calculated from it on demand. Deleting entries therefore also removes whatever was derived from them.

What is recorded

A song is added to the history when it counts as played, using the same rule as scrobbling: when you have listened to it for a set share of its length or a set number of seconds, whichever comes first. Skipping ahead in a song does not count as listening. The AI DJ’s spoken breaks are not recorded.

The rule is set under Settings → General → Scrobble:

SettingDefault
Scrobble minimum modePercentage or seconds (the first of the two). The other choices are Percentage and Seconds.
Minimum scrobble percentage75 %, adjustable from 25 to 90 %
Minimum scrobble seconds240 s, adjustable from 0 to 1200 s

Skips

When you leave a song for another one before it counts as played (Next, Previous, the album skip buttons, double-clicking another song in the queue, or starting another list), the history records a skip instead: the song, the position you left it at, the play mode and whether you or a DJ picked it. Leaving a song does not count as a skip when it was never really started (a restored queue you have not played yet), when Previous only restarts the song, or when the player moves on by itself: a DJ mix into the next song, the end of a song, or a song that failed to load (also when you start another song later, after a song ended on its own). Next on the last song of the queue stops playback and counts as a skip, because you left the song early. The AI DJ’s breaks and bridge songs are not recorded.

A skip is never a play: it does not count in the play numbers, the top lists, the mixes or Recently played, and it is never scrobbled. The Statistics page shows skips separately. A skip tells the DJs that a song did not fit at that moment.

The history works independently of the Scrobble switch: that switch only controls whether plays are reported to your server (for example to Last.fm).

Each entry stores the time, which server and song it was, whether it was played or skipped, the title, artists, album and length, and the cover address so that the list can be shown without asking the server. Newer entries also store the play mode, who picked the song (you, the Auto-DJ, the AI DJ) and which of your devices played it; skips store where in the song you left it. Songs from every source are recorded, including YouTube Music and local folders.

Settings

Open Settings → Advanced → History.

SettingWhat it does
Record listening historyOn by default. Off means nothing is written. What is already there stays until you delete it.
Don’t record this sessionPauses recording until you close Listen. This is the same switch as private mode, see below.
Keep history for1 year, 2 years or Unlimited (the default). Older entries are deleted automatically: when Listen starts, once a day while it runs, and right away when you change the setting. Choose Unlimited if you want year reviews of earlier years.
ExportJSON or CSV. Writes the whole history to a new file in your Downloads folder, called listen-history-<time>.json or .csv (the time is a Unix timestamp). A notification shows the path. If there is no Downloads folder, the file goes into Listen’s data folder.
Delete historyDelete all, then confirm with Yes, delete. This removes every entry and with it the statistics and mixes.

The CSV file has the columns timestamp (Unix seconds), server_id, source, song_id, status (played or skipped), title, artists (separated by semicolons), album and duration_secs. Text that a spreadsheet would read as a formula gets a leading apostrophe. The JSON file holds the same entries as a list.

The history itself is the file history.jsonl in Listen’s data folder; see Files and folders. You can back it up like any other file, and Backup, logs and diagnostics covers what else is worth keeping.

Private mode

Private mode stops three things at once: no entry is added to the history, no plays are scrobbled and Listen shows nothing on Discord. The window title says that private mode is on. It switches off again when Listen restarts.

Turn it on or off in any of these places; they all control the same switch:

  • Menu → Private mode in the sidebar’s app menu,
  • Settings → Window → Private mode,
  • Settings → Advanced → History → Don’t record this session.

Recently played

Recently played lists the last 500 plays, newest first, as an ordinary song list. Double-click a row to play from it. To forget a single play, right-click the row and choose Remove from history. If you have switched the history off, the page says so instead of listing songs.

Statistics

Statistics summarises what you listened to. Buttons at the top choose the period: Last 4 weeks, All time, or one of the years that have entries. Listen opens on Last 4 weeks; picking a year shows that year, or the newest year with entries if the chosen one has none. The heading reads “Your 2026 in music” for a year and “Your listening, all time” otherwise; this is the year review.

The page shows:

  • songs played: the number of plays in the period,
  • listening time: the full length of each song you played past the scrobble point, added up,
  • songs skipped: the number of skips in the period,
  • Top songs, Top artists and Top albums: ten each, with play counts. Songs and albums also show their artist; the others show the listening time. Where a song, artist or album was also skipped in the period, the row adds “N skipped”.

The ranking breaks ties by listening time and then by name. The artist chart counts every credited artist of a play, so a song with two artists counts for both.

Last 4 weeks

The rolling view compares this week with last week. The periods are rolling and end now: this week is the last 7 days, last week the 7 days before that, and 4 weeks the last 28 days.

  • Four tiles for this week: songs played, listening time, different songs and different artists, each with the change against last week (“+25 % vs last week”). When last week had nothing, the tile says “nothing last week”.
  • New artists this week: artists with a play this week and no play at all before it, most played first, with the first song you heard from them. A skip alone does not count as having heard an artist.
  • Skipped most (4 weeks): the songs you skipped most often in the 28 days, with how often you skipped and played them.
  • The last 4 weeks: plays, listening time and skips of the 28 days, then the top songs, artists and albums of that period, counted the same way as the year view.

Mixes

Mixes builds playlists of up to 50 songs from your history. Open one to see its songs and play it. Each row is a normal song row with the usual menus, so you can add the whole mix to a playlist from there.

MixWhat it contains
DaylistSongs you usually play around this time of day (within an hour of now).
Heavy rotationYour most played songs of the last 30 days.
RediscoverSongs you played at least twice before but not at all in the last 60 days. The ones you loved most (many plays, often close together) and have drifted furthest from come first.
All-time favouritesYour most played songs ever.

A mix without enough history behind it is greyed out and says “Not enough history yet”. Mixes change as you listen. They are made on your computer and need no server feature.

Learnable songs

With a vocab-hub address set (see Lyrics: known words), Mixes also shows Learnable songs: your liked songs where you know 90 to 98 % of the Korean words, the easiest first. Enough to follow the song, with a few new words to pick up. Songs with fewer than 20 Korean words are left out. Opening the mix loads your liked songs and looks up the lyrics of those not seen yet, a few at a time (the page shows how far it is); songs you played with lyrics are counted already. Songs without Korean lyrics are looked at again after 30 days. Every song’s words are kept in the cache folder (lyrics-words.json), so when you learn words in Lute the mix is counted again from there, without fetching lyrics again. Snoozed and “Not interested” songs stay out.

The artist page’s Top songs → Personal view uses the same history; see Library pages.

How Listen tells a forgotten favourite

Listen models how present each song is in your memory, after the ACT-R model from cognitive psychology: every play adds to a song’s “activation”, and the effect of a play fades with time (by the square root of its age). Many plays close together give a high peak; months of silence bring the activation down. A forgotten favourite has at least five plays, none in the last 30 days, and a large gap between its peak and its activation now. The Auto-DJ’s forgotten-favourite slot, the AI DJ’s song pool and the Rediscover mix use this ranking. A song you skipped again and again in the last week counts as worn out and rests from automatic picks for a while. Skips never count as plays.

listen --memory prints the current top 20 forgotten favourites and the resting songs as JSON (--history FILE, --now UNIX, --limit N).

Downloads

Downloads store copies of songs inside Listen so that you can play them without a network connection or when your server is down. This page explains which sources support it, how to download and remove songs, where the files are kept and what limits apply.

What can be downloaded

Offline downloads work for songs from Navidrome and other OpenSubsonic servers. Jellyfin servers and local folders do not offer downloads (a local folder is already on your disk). YouTube Music songs cannot be downloaded: Listen does not download YouTube Music songs for offline use, and it does not offer the command for them. Listen’s YouTube Music support is unofficial; see YouTube Music.

Note: Downloads are for your own server’s music. They are not a way to export your library to other programs. To save a normal file that you can use elsewhere, see Save file… below.

Downloading

Right-click a song, an album, a playlist or a selection (or use the three dots) and choose Download. Listen puts the songs in a queue and fetches them one at a time. While it works:

  • a notification says “Downloading 12 songs…”,
  • the Downloads page shows “Downloading “Title” (3 of 12)…” in blue,
  • when the batch is finished you get “Downloaded 12 for offline play.” Songs that failed are counted too, and listed on the Downloads page with the reason.

Songs you already have are skipped (“Already downloaded.”). If the server is not connected or has no download support, Listen says so.

Listen downloads the file as the server stores it, not a transcoded version.

The Downloads page

Downloads is always in the sidebar, below your pages. It lists everything that is stored, sorted by artist, album and track number, and shows how many songs there are and how much space they use, for example “12 songs · 480 MB”.

ControlWhat it does
A song rowClick to play the list from that song. The rows work like other song rows, including the right-click menu.
Bin button on a rowRemove download for that song.
Remove allDeletes every download.
Dismiss errorsClears the list of failed downloads shown under the title.

To remove downloads from the context menu, select songs that are all downloaded and choose Remove download; the same entry replaces Download in that case.

Removing a song while it is being fetched cancels it. Removing a server from Listen also deletes all downloads from that server.

Playing offline

Whenever a song has a downloaded copy, Listen plays the copy instead of streaming it, even when the server is reachable. This also saves traffic and keeps playback working on a bad connection.

If Listen starts and cannot reach any server, the connection screen offers Play downloaded songs (offline), which opens the Downloads page. That page works without a connection, and so does the player. Browsing the library, search, lyrics lookup from the internet and similar features need a server or internet connection as usual.

Where the files are

Downloads live in a folder named offline inside Listen’s data folder (see Files and folders), with the audio in offline/files and an index file that remembers the song details. The folder is private: on Linux only your user can read it. A download counts only when it is complete; unfinished files (.part) are cleaned up when Listen starts. The file names are made of the server and song ids, so the folder is not meant to be browsed or used by other programs.

Limits

  • Downloads are fetched one at a time, in the order you queued them.
  • Listen sets no size limit of its own; the limit is the free space on the disk that holds the data folder.
  • An empty or failed file is discarded and shown in the list of errors.
  • Downloads are tied to the server they came from. If you remove the server from Listen, its downloads go too.

Download versus Save file

The context menu has two similar entries on Navidrome, OpenSubsonic and Jellyfin:

EntryResult
DownloadA private copy inside Listen for offline playback (Navidrome and OpenSubsonic only).
Save file…The original file saved into your system Downloads folder, where you can use it with any program. Several songs of an album go into a folder named after the album.

See Lists, selection and menus for details.

Player bar and queue

This page covers the player bar at the bottom of the window, the seek bar (slider or waveform), and the play queue in all its forms: side panel, drawer and the Now Playing page. It also explains the queue tools, the difference between songs you queued and songs a DJ added, how the queue is restored, saving it to your server and the sleep timer.

The player bar

The bar has three columns. On the left are the cover and the song information, in the middle the transport buttons and the seek bar, on the right the extra buttons and the volume. When the window is 768 px wide or narrower, Listen switches to a compact bar with a smaller set of buttons.

Left: song information

  • Click the cover to open the full-screen player. The small arrow on the cover moves the cover into the sidebar and back.
  • The title is a link to the Now Playing page. Artists and album are links to their pages.
  • The ⋮ button next to the title opens the song menu. A right-click on the song information opens the same menu.
  • While a DJ transition runs, the third line reads “Mixing into …”. While the AI DJ talks, its name and its line are shown instead of the song.
  • While an internet radio station plays, the station name and the current stream title are shown.

Middle: transport buttons

From left to right:

ButtonWhat it does
StopStops playback.
Play modeCycles Off, Shuffle, Auto-DJ and AI DJ. See Play modes and Auto-DJ.
PreviousGoes to the previous song. More than 10 seconds into a song, it restarts the song instead. Alt+click jumps to the previous album.
Skip backwardJumps back by a fixed time (5 s by default).
Play / PauseStarts or pauses playback.
Skip forwardJumps ahead by a fixed time (10 s by default).
NextGoes to the next song. Alt+click jumps to the next album.
RepeatCycles Off, One and All. A highlighted button means repeat is on.
Shuffle all songsPlays a random selection of songs from the current server.

On a narrow bar, Listen first hides the skip buttons, then Stop and “Shuffle all songs”. A radio station keeps only Stop and Play.

The skip buttons, their durations and the button size are set in Settings → General → Player bar (Show skip buttons, Skip backward duration, Skip forward duration, Player bar button size).

Seek bar and times

The seek bar sits under the buttons. Click or drag to seek; the time on the left follows the drag and the seek happens when you release. The time on the right is the song length. Click it to show the time left (for example -2:31) instead; the setting Show remaining time does the same.

Seeking while a DJ transition is running cancels that transition.

Waveform seek bar

By default the seek bar is a plain slider. To show the loudness curve of the song instead:

  1. Open Settings → General → Player bar.
  2. Set Playerbar slider to Waveform.

The played part of the waveform is drawn in your accent colour. A click or drag seeks, as with the slider. These extra rows appear once you choose the waveform:

SettingRangeDefault
Waveform alignTop, Center, BottomCenter
Waveform bar width1 to 10 px2 px
Waveform gap0 to 10 px1 px
Waveform radius0 to 20 px4 px
Waveform stretchon or off; scales the bars to the full heightoff
Waveform loading delay0 to 10 s2 s

Listen calculates the waveform from the song’s audio, so it has to read the whole song once. For a song on a server this means an extra download, which is why the setting warns against the waveform on slow or metered connections. The result is cached, so a song is analysed only once. The loading delay postpones the calculation after a song change; raise it if you hear stutter when songs change.

Until the waveform is ready, and for songs without usable audio input, the plain slider is shown. A YouTube Music song gets a waveform only when a local copy of its audio already exists; the waveform never causes extra requests to YouTube.

Right: buttons, rating and volume

The right-hand buttons can be reordered and hidden in Settings → General → Player bar → Right-hand buttons. The available buttons are:

  • Sleep timer (see below).
  • Player config, shown as Player options: output device, playback speed and pitch. See Sound.
  • Visualizer and Lyrics: open the matching tab of the full-screen player.
  • Favorite: the heart. It is hidden when Show favourites is off in Settings → General → Lists.
  • Queue: shows or hides the queue panel (or drawer).
  • Volume: mute button and slider.

Some buttons appear on their own when they apply: the Show video / Show song switch for YouTube Music songs (Music videos) and the cast button when speakers or TVs were found (Casting).

Ratings. When the song’s server supports ratings (Navidrome and other OpenSubsonic servers; never YouTube Music) and Show ratings is on, five stars appear above the buttons. Click a star to rate the playing song; click the same star again to clear the rating. The hotkeys “Rate 0 stars” to “Rate 5 stars” do the same.

Volume. Click the speaker to mute. Scroll the mouse wheel over the slider to change the volume by the Volume wheel step (5 by default). The slider width is Volume slider width. A right-click on the speaker opens the list of audio output devices. While you cast to a device, the volume control sets the device’s volume.

Open on click. If you switch on Player bar opens full-screen player, a click on an empty part of the bar opens the full-screen player.

The queue

The queue is the list of songs that play next. It can hold songs from several servers at once.

Where the queue is shown

PlaceHow to open it
Side panelThe Queue button in the player bar (hotkey “Toggle queue”). The default.
DrawerChoose Detached for Side play queue style (below), then rest the pointer on the arrow tab at the right window edge, or press the Queue button to pin the drawer open. It slides in over the page and closes when the pointer leaves, unless you pinned it.
Now Playing pageClick the song title in the player bar, or enable Now Playing in the sidebar items (Settings → General → Sidebar). The page shows the whole queue at full width.
Full-screen playerThe Up Next tab.

Each place shows a header with the number of songs and the total time, a button naming the current play mode (a click moves to the next mode), and the queue itself.

Queue settings are in Settings → Playback → Queue:

SettingEffect
Side play queue styleAttached (a panel next to the page) or Detached (the drawer).
Side queue layoutHorizontal puts the queue in a column on the right, vertical puts it in a panel under the page. Drag the divider to resize.
Follow current songScrolls the queue to the playing song at each track change. On by default.
Up next queueLabels songs added with Play next and Add to queue as “Up Next”. On by default.
Confirm queue changesAsks before something replaces the queue or before the queue is cleared. Off by default.
Save play queueKeeps the queue between runs. On by default.
Autosave play queue to server and Autosave everySee Saving the queue to your server.

Settings → Playback → Player sidebar panels controls what the right-hand sidebar holds. Besides the queue it can show a lyrics panel, a visualizer strip, or both combined in one panel, and you can set the Panel order. Drag the dividers between the panels to resize them. The queue panel itself can be switched off as long as another panel stays on.

Working with the queue

  • Play a song: double-click it, or use the play button that replaces the number when you hover a row.
  • Reorder: drag rows up or down. Drag songs, albums or playlists from any list and drop them between the rows (or on the empty area under the last row) to insert them. You can also drop onto an empty queue to fill it.
  • Select: Ctrl+click toggles a row, Shift+click selects a range. See Lists, selection and menus for the details.
  • Remove: select rows and press Delete or Backspace. The playing song stays.
  • Search: the field in the toolbar filters the queue by title, artist, album or genre.
  • Right-click (or the row menu) offers Remove from queue, Move to top, Move to next, Move to bottom, Shuffle selected and Order for smooth mixing. The last one reorders everything after the playing song so that each song flows into the next (see Order for smooth mixing). The Up Next block is ordered within itself and still plays first; DJ bridge songs in that part are dropped, because they were chosen for their old neighbours.

Songs that were analysed for the DJ features show their tempo and key after the artist (“Artist · 124 BPM · 8A”).

Queue tools

The toolbar above the queue has these buttons:

ButtonWhat it does
Save queue to server / Restore queue from serverOnly on servers that keep a play queue. See below.
Shuffle queueShuffles the queue in three groups: the songs before the playing one, the Up Next block and the rest. The playing song keeps its place.
Clear queueEmpties the queue and stops playback. Asks first if Confirm queue changes is on.
Jump to playing songScrolls to the playing song.
Create playlist from queueStarts a new playlist with every song in the queue.
Search field and list optionsFilter the rows; the options button at the right end sets columns and similar list options.

In a narrow queue the buttons fold into a … menu, from the least to the most important one.

Queued songs and DJ songs

The queue distinguishes three kinds of songs:

  1. The rest of the queue: the songs of the album, playlist or list you started.
  2. Up Next: songs you added with Play next (they go to the top of the block) or Add to queue (they go to the end of the block). They play right after the current song, ahead of everything else. With Up next queue on, the block gets “Up Next” and “Queue” label rows; with it off, such songs carry a Queued tag until they play.
  3. DJ songs: songs the Auto-DJ or the AI DJ appended at the end. They carry an Auto or AI tag (a DJ bridge carries Bridge). Leaving the Auto-DJ mode does not remove songs it already added; delete them like any other song.

Why this song? Hold the pointer over the tag of a DJ song to see why it was picked. The Auto-DJ names one reason: a favourite you have not played for two months or more, “Similar to” the song its similar songs came from, “New to you”, or “Random pick from your library”. The AI DJ writes its own short note for every song of its set (at most 80 characters, in the DJ’s language, for example that the song keeps the key and lifts the tempo); a bridge says which two songs it links. Songs you added yourself have no reason. The reason of the playing song is also shown under the album in the full-screen player.

Dragging a row into the Up Next block adds it to the block; dragging it elsewhere takes it out. A marker row “AI DJ break” shows where the AI DJ will speak.

Player filters

Settings → Playback → Player filters keeps unwanted songs out of the queue. Press Add rule, then choose a field (title, artist, genre, year, play count, rating and others), an operator (for example contains, is, starts with, matches regex) and a value. A song that matches an active rule is left out when you play or queue it, and Listen says how many were kept out. Songs the Auto-DJ and AI DJ add are not filtered by these rules (use Snooze or Not interested for that, below). Each rule has an on/off switch.

Snooze, Not interested and Hide in this playlist

The menu of a song (in a list, in the queue and in the player bar) has three entries that keep it out of what Listen picks for you:

  • Snooze 30 days: for 30 days the Auto-DJ, the AI DJ, song, album and artist radio, DJ bridges and the mixes (Daylist, Heavy rotation, Rediscover, All-time favourites) leave the song out. Then it comes back by itself.
  • Not interested: the same, for good. For a YouTube Music song it also sends a dislike to YouTube Music, so its own suggestions learn from it (switch this off in Settings → Advanced → Hidden songs → Dislike on YouTube Music).
  • Hide in this playlist (only in a playlist): the song is left out when you play that playlist; other playlists, albums and the DJs are not affected. Show in this playlist takes it back.

Every version of a song counts (the single, the album track, the music video). A song you pick yourself always plays, even when it is snoozed, not wanted or hidden; double-clicking a hidden song in its playlist plays it. Upcoming songs a DJ already queued go from the queue when you snooze or reject them; the song playing now plays on.

Settings → Advanced → Hidden songs lists every snoozed (with the days left), not wanted and hidden song with an Undo button.

With Merge with other devices on (Settings → Advanced → Listening history), the hidden songs go to your listen-server right after each change and with every history merge, so the phone and your other computers leave the same songs out. When two devices change the same song, the later change wins. This needs listen-server 0.6.0 or newer.

Queue restore

With Save play queue on, Listen writes the queue and the position of the playing song to disk every few seconds and when you quit. At the next start the queue is back, the playing song is selected and the position is remembered, but nothing plays by itself. Press Play to continue where you stopped. Shuffle and repeat are restored as well.

Saving the queue to your server

Navidrome and other OpenSubsonic servers can store one play queue per user, so that another app can continue where you stopped. The two buttons appear in the queue toolbar when the server you are browsing supports this.

  • Save queue to server sends the songs of that server (songs from other servers are left out), the playing song and the position. A message tells you how many songs were saved.
  • Restore queue from server replaces your queue with the saved one. Nothing starts playing; the first Play resumes at the saved position. If Confirm queue changes is on, Listen asks before replacing.

To save automatically, switch on Autosave play queue to server in Settings → Playback → Queue and set Autosave every (1 to 20 track changes; default 1).

Sleep timer

The Sleep timer button (a clock icon) in the player bar opens a small panel:

  • End of song pauses at the end of the playing song.
  • End of album pauses once the album of the playing song is over. If you start another song yourself, the timer follows that song’s album. It is not available while Shuffle is on.
  • The grid starts a timer of 5, 10, 15, 30, 45, 60, 120, 180 or 240 minutes.
  • Custom takes hours, minutes and seconds (up to 23 h 59 min 59 s).

While a timed timer runs, the remaining time is shown on the button. The countdown only runs while music plays, so pausing does not use up your time. When the timer ends, playback pauses and Listen shows a short message. Cancel in the panel turns it off. The sleep timer is not kept when you quit Listen.

Play modes and Auto-DJ

Listen has one button that decides what happens when the queue runs low: stop, shuffle, add similar songs (Auto-DJ) or let the AI DJ take over. Repeat is a separate button. This page explains both and the Auto-DJ settings.

The play mode button

The play-mode button sits in the player bar next to Stop. The same button appears in the header of the queue and on the Now Playing page, labelled with the current mode. Each click moves to the next mode:

Off, Shuffle, Auto-DJ, AI DJ, and back to Off.

The tooltip shows the current mode and the one a click leads to (“Play mode: Shuffle → next: Auto-DJ”). The “Toggle shuffle” hotkey, the media-key integration and the remote-control page use the same cycle. The MCP server’s set_play_mode tool can pick a mode directly. A highlighted button means any mode other than Off is on.

The modes exclude each other. If several settings were on together (for example from an older configuration), the order of priority is AI DJ, then Shuffle, then Auto-DJ.

ModeWhat happens
OffThe queue plays in order and stops at its end.
ShuffleThe play order of the queue is shuffled. The playing song keeps playing, and songs in the Up Next block still come first, in the order you queued them. Switching away from Shuffle restores the original order.
Auto-DJWhen few songs are left, Listen appends similar songs to the queue.
AI DJGemini picks sets of songs and talks between them. Needs your own Gemini API key.

A new installation starts in Auto-DJ. The first-start wizard can turn it off.

Note: The AI DJ is skipped in the cycle until a Gemini API key is saved. If you choose it anyway (for example through MCP), Listen shows a hint to add a key in Settings → Playback → AI DJ. See AI DJ and Creating a Gemini API key.

Shuffle changes the order of the queue itself, so you see the new order in the queue panel. The sleep timer’s End of album option is not available while Shuffle is on.

With the AI DJ on, clicking a single song in a list plays that song alone and makes it the new mood for the DJ’s next set, instead of queueing the whole list.

Repeat

The repeat button cycles Off, One, All:

  • Off: the queue stops after its last song.
  • One: the playing song repeats. Pressing Next still moves on, but stays on the last song instead of wrapping around.
  • All: after the last song the queue starts again from the top.

The button is highlighted whenever repeat is on, and shows a “1” symbol for One. The hotkey is “Toggle repeat”.

Auto-DJ

The Auto-DJ keeps the music going without you filling the queue. It watches how many songs are left after the playing one. When at most one song is left, it asks the server of the playing song for songs similar to it, adds a few random songs as filler, and appends the best candidates to the end of the queue. Songs it added are tagged Auto-DJ in the queue. See Player bar and queue.

Details:

  • Songs that already played in this session, and songs already in the queue, are not added again.
  • Where a song exists in several versions (for example a studio version and a live version), one version is picked, preferring the radio edit.
  • If songs were analysed, the picks are ordered so that tempo, key and energy follow on from the playing song. The Auto-DJ then looks at more candidates before choosing.
  • With DJ transitions on, songs the Auto-DJ picked are mixed into each other.
  • Forgotten favourites: every eighth song the Auto-DJ adds is one of your favourites that you have not played for at least 30 days (at least five plays in your history). Of those, the one whose tempo, key and energy fit the playing song best is taken. Its reason in the queue reads “A favourite, not played for 5 months”. Without such songs in your history the slot gets an ordinary pick.
  • Worn-out songs rest: a song you skipped three times in the last seven days (or twice, if you also played it a lot that week) is left out of the Auto-DJ, the AI DJ, radio, DJ bridges and the mixes until those skips are more than a week old. You can still play it yourself at any time.
  • Learn from my skips: how much a tempo gap, a key clash, an energy jump, a change of sound, a hard cut or a repeated artist count when the DJ orders its picks is learnt from your own listening. Every time a song you were playing hands over to one the Auto-DJ, AI DJ, radio or Rediscover picked, Listen notes whether you skipped the new song within 30 seconds. From these handovers (on every device, the history is synced) it fits how strongly each of those terms goes with an early skip, and weighs them that way. Until 300 handovers are recorded the learnt weights are mixed with the built-in ones in proportion (100 handovers: one third learnt), and below 300 a term can only count more or less, never the opposite way; below 30 handovers the built-in weights are used unchanged. A term your history says nothing about (for example no same-artist handovers yet) keeps its built-in weight. The fit is redone every ten plays or skips and kept in flow-weights.json next to the history. With Merge with other devices on, the fit also goes through your listen-server: the newest fit of any device is used everywhere, so the computer and the phone weigh the same way (a device that has not learnt anything yet never replaces a learnt fit with the built-in weights; needs listen-server 0.10.0 or newer). Turning the setting off brings back the built-in weights exactly. listen --flow-weights prints the number of handovers, the cross-validated AUC of the learnt weights next to that of the built-in ones, and each weight.
  • What “similar” means depends on the server: Navidrome and Jellyfin use their similar-songs lists, YouTube Music uses its “watch next” list.

Settings

Open Settings → Playback → Auto-DJ:

SettingDefaultMeaning
EnabledonSwitches the Auto-DJ on or off. Same as choosing the mode.
Songs to add5 (1 to 20)How many songs are added at a time.
Forgotten favouritesonOne song in eight is a favourite you haven’t played for a while (see above).
Learn from my skipsonThe flow scorer’s weights learnt from the songs you skip early after a handover (see above).

Three more options exist that have no control in the settings window. They live in the configuration file under [settings.auto_dj] (see Files and folders), can be changed through the MCP server’s set_settings tool, and are filled in when you import your settings from Feishin:

KeyDefaultMeaning
timing1The Auto-DJ refills when this many songs or fewer are left after the playing one.
allow_duplicatesfalseAllows songs that are already in the queue to be added again.
strategy"similar""similar" asks for similar songs first; "random" only adds random songs.

Edit the file only while Listen is closed.

Focus

Focus is for working or reading while music plays: songs with lyrics distract most there. The Focus button sits next to the play-mode button at the top of the queue (and on the Now Playing page). It shows in Auto-DJ and AI DJ mode, and always while Focus is on. A green button means Focus is on; Listen remembers it.

With Focus on:

  • The Auto-DJ and the AI DJ prefer songs with little lead vocal and calm energy. Listen knows how much of a song is sung from the analysis (the vocal level of every bar). Besides the similar songs, the Auto-DJ also looks at the least sung analysed songs in your history, so each fill finds quiet songs even when the similar ones are all sung. Songs without an analysis come last.
  • A sung song the Auto-DJ picked is swapped for its instrumental version when its source has one (for example “Love (Inst.)” on YouTube Music, or an instrumental track on a Navidrome album). Listen searches for “title artist inst.” for up to three songs per fill; when that finds no instrumental it searches once more for plain “title artist” (some Navidrome searches miss “(Instrumental)” tracks with the extra word). The swapped song keeps its place in the queue, and its reason reads “Good for focus”.
  • The AI DJ does not talk: no voiced breaks, not even planned ones. It still chooses and mixes the songs.
  • No forgotten-favourite slot (a forgotten favourite is rarely a quiet one).
  • Turning Focus on removes upcoming DJ songs that are sung, except the next one (it may already be mixing in). Songs you queued yourself stay.

Songs you start yourself always play as they are. Turn Focus off and the next fill is an ordinary one again. The MCP server’s set_focus tool switches it, and get_state reports it as focus.

listen --focus checks Focus on your own data: it splits your history’s analysed songs into Auto-DJ-sized candidate pools and prints, as JSON, the mean sung share of eight ordinary five-song fills and of eight Focus fills, and their ratio (--history FILE, --store DIR, --fills N, --per-fill N, --pool N, --seed N). Instrumental swaps come on top of that number.

Heart-rate tempo

The heart button next to the play-mode button plays songs whose tempo fits your heart rate, from a Bluetooth heart-rate sensor. In Off or Shuffle it switches to Auto-DJ. See Heart-rate tempo.

Heart-rate tempo

Heart-rate tempo plays songs whose tempo fits your heart rate, for a run, a ride or a workout at home. It needs Bluetooth on the computer and a Bluetooth heart-rate sensor that uses the standard Heart Rate Service: most chest straps do, and so do watches that can broadcast their heart rate. Listen does not stretch songs to the beat. It only chooses songs that already fit.

Music does not measurably change your heart rate during exercise. The mode picks music that fits your effort. It is not training guidance.

Switching it on

The heart button sits next to the play-mode button in the player bar, and next to the repeat button in the narrow full-screen player. You can switch it at any time. The song that plays keeps playing. The button is highlighted while the mode is on, and once readings come in it shows the target tempo (“142”). Its tooltip shows the status:

  • Heart-rate tempo off
  • Looking for a heart-rate source…: Listen is scanning for a sensor.
  • No heart-rate source found: no sensor is in range, or Bluetooth is off or missing. Listen keeps looking every few seconds, and everything else works as usual.
  • Heart-rate tempo on: readings come in. The tooltip also shows the target and the sensor’s name.

The Toggle heart-rate tempo hotkey, the switch in Settings → Playback → Heart-rate tempo and the MCP server’s set_heart_rate tool switch it too.

The tempo needs a DJ to choose the songs. In Off or Shuffle, switching the mode on also switches the play mode to Auto-DJ. In AI DJ the AI DJ keeps going. Switching the mode off leaves the play mode as it is.

The sensor

When the mode is on, Listen scans for a Bluetooth device that offers the Heart Rate Service. It connects to the first one it finds and subscribes to its heart-rate readings. The sensor is not paired with the computer. Listen remembers the sensor and looks for it first next time. Other sensors are only taken when it doesn’t show up within a few seconds. Settings → Playback → Heart-rate tempo → Forget sensor clears the remembered one. If the link drops (out of range, strap taken off), Listen connects again on its own.

Wear the strap before you switch the mode on. Most straps only send while they have skin contact.

On Linux, Listen talks to BlueZ (the system’s Bluetooth service) over D-Bus. On Windows it uses the system Bluetooth stack. The computer needs Bluetooth Low Energy (Bluetooth 4.0 or later). Step cadence (the phone app’s mode without a sensor) is not available on the computer.

How songs are chosen

Readings are smoothed over about 30 seconds, so one odd reading doesn’t change the music. The target is your heart rate in beats per minute, clamped to 70–180, ± 8 BPM. Half and double time count: at 150 a 75 BPM song fits, and at 70 a 140 BPM song fits. The fit is judged at the faster pulse, so at 70 the songs that fit are 62–78, 132–148 and 31–39 BPM. A 130 BPM song does not fit 70: it is 10 BPM off 140. Tempos come from the song analysis. Songs without one count as unknown, unless their tags give a BPM.

  • Re-ranking. When the target has moved more than 5 BPM since the last time, the upcoming songs the DJs picked are sorted again. Songs within 4 BPM stay, closest tempo first, and the rest are taken out. The song right after the current one also stays, because it may already be loaded or mixing in. Songs you added yourself are never touched.
  • Fills. Every Auto-DJ fill and every AI DJ set aims at the target. The fetched candidates that fit come first. When too few fit, Listen tops them up from the analysis store: songs from your history and analysed YouTube Music songs that fit, closest to the current song’s sound. Songs that are queued, played this session, snoozed, hidden (“Not interested”) or resting as worn out never come back this way. Only when even the store has too few does the fill pad with the nearest songs that don’t fit, so the music never stops. The log says so: heart-rate tempo: only N songs fit 142, padded with M nearest.
  • Same scene. A song the fill adds from the store must belong to the music that is playing: the scene (language, genre and era) most of the current song and the songs around it share, or one of them when you are mixing scenes. A K-pop set never gets a British pop, Japanese anime or 1990s song this way, nor one whose scene Listen can’t tell. Eras count by decade: the 2010s fit the 2020s, the 1980s don’t. Songs you have played come before songs you have never heard. When too few songs fit, the fill takes fewer of them and keeps the DJ’s own songs, rather than reaching into another scene. The log line: heart-rate tempo: 9 fit 146, 31 rejected (other scene 20, other era 3, unknown 8) [session scene ko · pop · 2020s …].
  • AI DJ. The AI DJ is told that heart-rate mode is on and the tempo is a hard requirement. Every candidate is marked “tempo fits the heart rate” or “tempo does NOT fit the heart rate, avoid”.
  • Why this song. Auto-DJ picks that fit read “Matches your tempo: 142 BPM” (see Why this song?).
  • The forgotten-favourite slot is skipped while the mode is on, because an old favourite at another tempo would break the run.

Switch the mode off and the next fills are ordinary again. Tempo picks already in the queue stay.

Testing without a strap

LISTEN_HR_FAKE=70:180,150:300,90:300 listen replaces the sensor with a scripted source: steps of bpm:seconds, one reading per second, repeated. Demo mode (listen --demo) plays this rest, run and cool-down curve by default. The MCP tool set_heart_rate takes on and sample_bpm, which feeds one reading as if it came from the sensor. get_now_playing reports the mode as heart_rate: on, status, the last bpm, the smoothed rate, the target, the source, the remembered sensor, the number of reranks and what the last_fill took.

Sound

Listen plays through mpv, so most sound settings map directly to mpv features. This page covers the output device, gapless playback, volume levelling, ReplayGain, the equalizer and compressor, speed and pitch, fades, streaming quality and transcoding, extra mpv options, and the server jukebox.

Most of these settings are in Settings → Playback, in the sections Playback, Audio output, Volume levelling, ReplayGain, mpv, Equalizer, Headphone correction, Compressor and Transcoding. Output device, speed and pitch are also in the Player options popover (the sliders icon in the player bar).

Note: Equalizer, headphone correction, compressor, volume levelling, ReplayGain, speed, pitch and fades are applied by mpv on this computer. They have no effect while you cast to a device or use the server jukebox.

Output device

To choose where sound comes out:

  • Settings → Playback → Audio output → Audio device, then Refresh if the device is not listed; or
  • right-click the speaker icon in the player bar; or
  • use Audio device in the Player options popover.

The first entry, System default, follows the operating system’s default device. The other entries are the devices mpv reports. If the list cannot be read, the error is shown under the row.

More output options in the same section:

SettingMeaning
Sample rateOutput rate in Hz, for example 48000. Empty (or below 8000) uses the device default. Press Enter or Apply.
Exclusive modeTakes the sound device for Listen alone (mpv audio-exclusive; WASAPI on Windows and some ALSA setups). Other programs are silent meanwhile. Off by default.
Audio formatSample format sent to the sound card: auto, s16, s32, float or u8.
Preserve pitch, Microtonal pitch controlsSee Speed and pitch.

Gapless playback

Settings → Playback → Playback → Gapless playback sets mpv’s gapless-audio:

  • weak (default): gapless, except when the audio format changes between two songs.
  • yes: always gapless.
  • no: a short gap between songs.

Listen prepares the next song while the current one plays, so albums and playlists play without a break. Crossfading between songs is not available as a setting; the DJ transitions blend songs that the Auto-DJ or AI DJ picked, and albums stay gapless.

Track fades

Two settings in the Playback section smooth the start and end of songs:

  • Fade songs in and out: each song fades in at its start and out at its end over this time. Range 0 to 10 s in steps of 0.5 s; default 1.5 s; 0 turns it off. The AI DJ lowers and raises the music at this speed too (at least 1 s).
  • Fade on pause: fades out briefly when you pause and back in when you resume. On by default.

Volume levelling

Volume levelling plays every song equally loud, so a quiet ballad after a loud dance track needs no hand on the volume. It is on by default. Choose the level in Settings → Playback → Volume levelling → Level:

LevelLoudness
OffSongs play as they are (ReplayGain applies, if set).
Quiet−19 LUFS: room for very dynamic music.
Normal (default)−14 LUFS, the level streaming services use.
Loud−11 LUFS.

How loud a song is comes from the first of these that knows it:

  1. the analysis of the song (its measured loudness),
  2. YouTube’s own loudness value, for YouTube Music songs that are not analysed yet (Listen asks YouTube once per song),
  3. the song’s ReplayGain tags,
  4. nothing: the song plays unchanged.

Loud songs are turned down as far as needed; quiet songs are turned up by at most 6 dB, and a limiter at the end of the sound chain keeps boosted peaks below −1 dB, so nothing clips. Changing the level while a song plays glides to the new loudness instead of jumping. Get info on a song shows the gain it gets and where its loudness came from (row Volume levelling); the log names it too (levelling: <title> −4.2 dB from analysis).

While volume levelling is on, it replaces ReplayGain (it reads the ReplayGain tags itself), so the ReplayGain settings below only matter with Off.

ReplayGain

ReplayGain evens out the loudness of songs that carry ReplayGain tags. In Settings → Playback → ReplayGain:

SettingMeaning
ModeOff (default), Track (each song to the same loudness) or Album (keeps the loudness differences inside an album).
PreampGain added on top of the ReplayGain value, -15 to +15 dB.
Prevent clippingLowers the gain if the peak would exceed full scale. On by default.
Fallback gainGain in dB for songs without ReplayGain tags, -15 to +15 dB.

Equalizer

The equalizer has twelve bands at 31.5, 63, 125, 250, 500 Hz and 1, 2, 3, 4, 6.3, 10 and 16 kHz, each from -12 to +12 dB in steps of 0.5 dB, plus a Pre (preamp) slider with the same range.

To use it:

  1. Open Settings → Playback → Equalizer and switch Equalizer on.
  2. Drag the sliders, or pick a preset under Presets.

The built-in presets are Acoustic, Bass Boost, Bass Cut, Classical, Electronic, Flat, Hip-Hop, Jazz, Loudness, Pop, Rock, Treble Boost, Treble Cut, V-Shape and Vocal Boost. Choosing a preset sets the bands and resets the preamp to 0.

To save your own preset, set the bands, type a name into Save current as… and press Save. A saved preset appears in the list after the built-in ones, can be deleted with Delete, and takes precedence over a built-in preset of the same name. Reset sets all bands and the preamp back to 0.

Headphone correction

Headphone correction bends your headphones’ sound toward a neutral target, using the measured profiles of AutoEq (MIT licence). About 6000 headphone models are built into Listen, one profile per model (measurements by oratory1990 first, then crinacle, then the other sources), so nothing is downloaded. The correction runs first in the sound chain, before the equalizer, so the equalizer stays your own taste on top of a neutral sound.

A profile belongs to an output, not to Listen as a whole:

  1. Play through your headphones (connect them, or pick them as the Audio device).
  2. Open Settings → Playback → Headphone correction. This output names the output that plays now.
  3. Type the model into Find your headphones (for example WH-1000XM5 or HD 600; hyphens and case don’t matter) and pick it. When the output’s name already says which headphones it is (Bluetooth headphones usually do), Listen suggests the profile before you type.

From then on the profile is applied whenever that output plays, and taken off when another one does. With the audio device on Autoselect, Listen follows the system’s default output (on Linux: pactl get-default-sink, checked twice a second), so connecting Bluetooth headphones or plugging in a wired pair switches the profile within a second. While a DJ transition plays (from loading the next song until the blend has ended) the switch waits and then uses the output that plays at that moment; a transition that is only planned doesn’t hold it up.

On Android the same section is in Settings, above the Equalizer. The phone binds a profile to the output media plays on (Bluetooth, wired, USB or the speaker, by the device’s name), so the same headphones over Bluetooth and over a cable are two outputs, and a switch applies at once, also during a transition.

You can also paste the text of an AutoEq or Equalizer APO ParametricEQ.txt into the search box and choose Use pasted profile. Other outputs lists the profiles bound to outputs that don’t play now; Remove takes one away. Headphone correction (on by default) turns all of them off without forgetting them.

Every profile keeps its preamp, lowered further when a band boosts more than it leaves room for, so the correction itself never clips; volume levelling’s limiter comes after it as usual.

Compressor

The compressor evens out loud and quiet passages. It uses ffmpeg’s acompressor filter inside mpv. It runs after the equalizer.

Switch Compressor on in Settings → Playback → Compressor, then pick a preset (Broadcast, Default, Gentle, Heavy, Light, Limiter, Loud Master, Moderate) or set the values:

SettingRangeWhat it does
Threshold-60 to 0 dBThe level above which compression starts.
Ratio1 to 20 (n:1)How strongly loud parts are reduced.
Attack0.1 to 2000 msHow fast the compressor reacts.
Release1 to 9000 msHow fast it lets go again.
Makeup gain0 to 30 dBGain added after compressing.
Knee1 to 8 dBWidth of the soft knee around the threshold.

Your own compressor presets work like the equalizer presets: type a name, press Save.

Speed and pitch

Open the Player options popover (sliders icon in the player bar). Playback speed runs from 0.5x to 2x. Press 1x to reset. For songs that have been analysed, the readout also shows the resulting tempo, for example 1.25 x / 150.0 BPM.

By default Preserve pitch is on: the music gets faster or slower and keeps its pitch. Switch it off (in the popover or in Settings → Playback → Audio output) to let speed and pitch move together, like a record. Then a row of pitch buttons appears:

  • -1st and +1st change the pitch by one semitone.
  • With Microtonal pitch controls on (Settings → Playback → Audio output), -10ct and +10ct change it by ten cents.

The readout between the buttons shows the speed and the pitch shift, for example 1.12x +1.96st. Pitch steps are speed steps: a semitone is a speed change by the twelfth root of two, within the 0.5x to 2x limit.

Note: The speed controls are disabled while DJ transitions are possible, because the transitions change the songs’ speed to match their tempos. That is the case when DJ transitions is on and the Auto-DJ or the AI DJ is on, which is the default setup. To change the speed, switch DJ transitions off in Settings → Playback → DJ transitions & song analysis, or leave the Auto-DJ and AI DJ modes (for example choose Off). Speed and pitch have no effect while casting.

Streaming quality and transcoding

Streaming quality (Settings → Playback → Playback) limits the bit rate to save bandwidth:

ChoiceLimit
Original (best)The file as stored. Default.
High (320 kbit/s)Up to 320 kbit/s.
Normal (192 kbit/s)Up to 192 kbit/s.
Low (96 kbit/s)Up to 96 kbit/s.

On Navidrome the server converts the song to MP3 up to the chosen rate; YouTube Music picks a smaller audio format. Local files, downloaded songs and the copies used for DJ analysis stay original.

If you want control over the format, use the Transcoding section. It appears when you have at least one server that is not YouTube Music. Switch Transcode on to ask Navidrome or Jellyfin to convert songs while streaming. It replaces Streaming quality for those servers; YouTube Music keeps that setting. New values apply to songs that start from then on.

SettingMeaning
Formatmp3, opus, flac and so on. Empty lets the server choose (Jellyfin: MP3).
Maximum bit rateIn kbit/s; 0 or empty lets the server pick.
Maximum sample rateIn Hz, Jellyfin only; empty means no limit.

mpv: executable and extra options

The mpv section of Settings → Playback is for special cases:

  • Executable path: the mpv program to run. Empty uses mpv from your PATH. On Windows the setup wizard and Settings → Advanced → Helper programs manage mpv for you.
  • Extra parameters: extra mpv options, one per line, for example --audio-channels=stereo. A missing leading -- is added for you. See the mpv manual for options.
  • Reload mpv: stops playback and starts mpv again with the path and parameters above. Changes to path and parameters need this step. The Player options popover has a Reload button too.

Wrong parameters can stop playback from working. Clear the box and reload to go back to the defaults.

Jukebox mode

Some Subsonic-style servers can play music through their own speakers, controlled by a client. If the server answers Listen’s jukebox request, an Audio player row appears at the top of Settings → Playback → Playback:

  • mpv (this computer) is the default.
  • Jukebox (the server plays) hands the queue, starting at the playing song, to the server. Listen then only controls it: play, pause, stop, seek and volume are sent to the server, and the position is polled every two seconds.

The server administrator has to switch the jukebox on first. Listen sends up to 100 songs of the playing song’s server at a time. Equalizer, compressor, ReplayGain, speed and the DJ features do not apply to the jukebox. If the server turns out to have no jukebox, Listen plays with mpv again and tells you.

Full-screen player and Now Playing

The full-screen player shows the cover large with the song details, and one panel next to it: the queue, similar songs, lyrics or the visualizer. This page also covers its settings, the idle auto-open and the Now Playing page.

Opening and closing

Open the full-screen player in any of these ways:

  • Click the cover in the player bar.
  • Press the Lyrics or Visualizer button in the player bar. They open the full-screen player on that tab.
  • Use the hotkey Toggle full-screen player (see Hotkeys).
  • Switch on Player bar opens full-screen player (Settings → General → Player bar) and click an empty part of the bar.
  • Switch on the song/video switch for a YouTube Music song (Music videos); the video is shown here.

Close it with the Minimize button (the arrow at the top left), the same hotkey, or Esc.

When nothing is playing, the window says “Nothing is playing.”

What you see

The top-left corner has two buttons: Minimize and Configure (the gear, see below). The top-right corner has five tab buttons:

TabContent
Up NextThe play queue, with the same toolbar as the side panel. See Player bar and queue.
RelatedSongs similar to the playing one (up to 50), when the song’s server can provide them. Right-click or use the menu on a row as usual.
LyricsThe lyrics with their buttons.
VisualizerThe visualizer (spectrum, or Milkdrop where available).
AboutFacts about the playing song and its credits, see below.

Click a tab to open its panel; click it again to close the panel, and the cover moves to the middle. One panel is open at a time.

On the left are the cover (or the music video) and, under it, the title, the artists, the album and badges with technical details such as the codec. The title and the artists are links. A long title scrolls like a marquee unless you chose wrapped titles. When a DJ picked the playing song, a line under the album says why (see Why this song?).

The background takes its colour from the cover and changes with each song.

The visualizer tab has an Expand visualizer button at its top right that fills the whole window with the visualizer, with the song name in a corner. Use Shrink visualizer or Esc to go back.

About this song

The About tab shows three to five short facts about the playing song (what the title and the lyrics mean, how it was made, its release and how it was received), in the app language. Gemini writes them with Google Search, using the AI DJ’s key and text model (see Gemini key); without a key the tab says so. Every fact carries links to the web pages it rests on, and a fact without such a link is left out. If nothing with a source is found, the tab says so instead of showing a card. Searched for links the searches Gemini made to Google.

Under the facts are the Credits (writer, composer, lyricist, arranger, producer, mixing, engineer) from MusicBrainz, with a link to the recording there. Listen uses the song’s MusicBrainz recording id when your server has it, and otherwise searches MusicBrainz by title and artist. Many recordings, K-pop especially, have no credits there yet; then this part is missing.

The card is fetched when the tab is open (and again when the song changes while it is open), then kept for 30 days per song and language. Look it up again fetches a fresh one. One card costs up to three Gemini requests: when Gemini’s answer comes back without source links, Listen asks again.

In a narrow window (768 px or less) Listen uses a phone-style layout instead: a header, the cover, the details, a progress bar and the transport buttons, and a bottom row with shuffle, repeat, queue and lyrics. The queue and the lyrics replace the cover while they are open.

Settings of the full-screen player

There are two places:

  1. Settings → General → Full-screen player has Full-screen auto-open timeout and Configure…. The same dialog opens from the gear inside the player.
  2. Configure opens the dialog Full-screen player. Changes apply live behind the dialog; press Done to close it.
SettingRangeDefaultMeaning
Dynamic backgroundon or offonColours the background from the cover. Off uses the theme background.
Use the cover as backgroundon or offoffShows the blurred cover instead of a flat colour.
Image blur0 to 6 rem6Blur of that image.
Opacity0 to 100 %25How strongly the background is darkened.
Use the cover’s aspect ratioon or offoffShows non-square covers whole, instead of cropping them to a square.
Cover size55 to 100 %75Cover width as a share of its column. The cover also never gets taller than the room above the song details.
AlignmentLeft, Center, RightCenterWhere the cover and the text sit in their column.
TitleScrolling or WrappedScrollingOne line that scrolls when too long, or a title that wraps.
Title lines1 to 101Lines for a wrapped title. Shown only for Wrapped.
Metadata badgescheckboxesCodec, Release yearThe badges under the title.

The available badges are Codec, Bit rate, Bit depth, Sample rate, BPM, Year, Release year, Date, Release date, Release type, Genres, Disc number and Track number. A badge is skipped when the song has no data for it.

Auto-open

To open the full-screen player on its own, for example when the computer acts as a music display, set Full-screen auto-open timeout to a number of minutes (1 to 120). After that many minutes without a mouse move, click, scroll or key press, while a song is playing, the player opens. Press Esc to return. The default, 0, switches the feature off.

Now Playing page

The Now Playing page is the queue as a full-width page, with the same toolbar and tools as the side panel. It also shows the number of songs, the total time and the play-mode button. Open it by clicking the song title in the player bar. To add it to the sidebar, enable Now Playing in the list of items in Settings → General → Sidebar; it is hidden by default.

While the page is open, the side panel and drawer are not shown, since the page already shows the queue.

Lyrics

Listen shows the lyrics of the playing song, highlights the line being sung and, when the lyrics carry word timings, the word. It can search other providers by hand, translate lines, show Japanese readings and export lyrics to a file.

Where to see lyrics

  • The Lyrics button in the player bar opens the full-screen player on its Lyrics tab.
  • A lyrics panel in the right sidebar: switch on Lyrics panel in Settings → Playback → Player sidebar panels. It can sit under the queue, or share one panel with the visualizer (Combine lyrics and visualizer).

Lyrics that follow the song (“synchronized”) scroll along and light up the current line. Plain lyrics without timing are shown as static text. If no lyrics are found, the view says “No lyrics found for this song.”

Where lyrics come from

When a song starts, Listen looks for lyrics in this order:

  1. A lyrics version you picked by hand for this song earlier (see Search).
  2. The song’s own server: Navidrome and other OpenSubsonic servers, and YouTube Music, can provide lyrics themselves.
  3. The online providers you enabled.

With Prefer local lyrics on (the default), the server’s or YouTube Music’s synchronized lyrics are used without asking any provider. Plain server lyrics give way to synchronized lyrics from a provider. With it off, a provider result wins whenever one is found.

The providers are asked one after the other in your order. The first that has synchronized lyrics for the song wins. If none has, the best plain-text match of the earliest provider is used. A result is only trusted if title and artist are close enough to the playing song.

ProviderNotes
NetEaseOften has synchronized lyrics, sometimes word by word, and its own translations. Enabled by default, asked first.
lrclib.netA community database of synchronized and plain lyrics. Enabled by default, asked second.
GeniusPlain lyrics only. Off by default.
SimpMusicA community lyrics service. Off by default.

Each lookup sends the song’s title, artist, album and length to the providers you enabled. Nothing is sent when Fetch lyrics is off. While DJ transitions mix songs, the next song’s lyrics are looked up ahead too, to find where its singing starts.

To change this, open Settings → Playback → Lyrics:

  • Fetch lyrics turns the lookup on or off. It covers the server’s lyrics as well as the providers. With it off, Listen finds no lyrics, apart from versions you picked by hand.
  • Lyric providers lists the four providers. Use the switch to enable one and the arrows to change the order.
  • Prefer local lyrics, as described above.

The Show the provider and Show the match switches in the display settings add a line naming where the lyrics came from (and which song the provider matched).

Using the lyrics view

Under the lyrics are two rows of buttons:

ButtonWhat it does
EXPORTSaves the lyrics to a file (see below). Shown when lyrics are loaded.
Version listAppears when more than one version was found (for example from the server and from a provider). Pick one; each entry names its provider and whether it is synced or plain.
TRANSLATIONShows or hides translations under each line. Appears when the lyrics carry a translation or when you set up an online translation service.
WORDSKorean lyrics with the Gemini key of the AI DJ: makes every Korean word clickable for its meaning (see Word meanings).
DISPLAYOpens the display settings.
SEARCHOpens the lyrics search.
− / number / +Moves the lyrics against the music in steps of 50 ms (tooltips “Lyrics earlier” and “Lyrics later”). You can also type a value.
CLEAR / REFRESHCLEAR removes the lyrics of this song, including a version you picked. REFRESH looks for them again.

Offset

The number between − and + is the shift in milliseconds for this song. The default for all songs is Lyric offset in Settings → Playback → Lyrics (-2000 to 2000 ms, default 0). A per-song change lasts for the current session.

Searching for other lyrics

If the automatic lookup picked the wrong song or no lyrics:

  1. Press SEARCH. The title and artist of the playing song are filled in.
  2. Change them if needed and press Enter or Search. Every enabled provider is asked at once.
  3. Select a result to preview it. Results are sorted with synchronized ones first, and marked synchronized or unsynchronized.
  4. Press Apply to use it. Listen remembers your choice for this song, also after a restart.

Export in this dialog saves the previewed result.

Display settings

DISPLAY (and the same rows at the end of Settings → Playback → Lyrics) sets:

SettingRangeDefault
AlignmentLeft, Center, RightCenter
Lyric size (synchronized), (unsynchronized)8 to 72 px24 px
Lyric gap (synchronized), (unsynchronized)0 to 50 px24 px
Left padding, Right padding0 to 50 % of the width0
Follow the current lyricon or offon
Follow position-50 (top) to 50 (bottom)0 (centred)
Line lead time0 to 3000 ms800 ms
Opacity of other lines0 to 100 %20 %
Size of other lines50 to 100 %95 %
Show the match, Show the provideron or offoff, on

Line lead time makes a line light up that many milliseconds before its time stamp, so you can read ahead. Lines in right-to-left scripts such as Arabic and Hebrew are aligned to the right.

Karaoke highlighting

When lyrics have word timings (enhanced LRC files, or NetEase’s word-by-word format), the words of the current line light up as they are sung. There is no setting for this; it happens whenever the lyrics contain word timings and are synchronized.

Japanese: romaji and furigana

Two optional extras help with Japanese lyrics:

  • Romaji shows the line in Latin letters under it. Kana are converted directly; kanji are read through the built-in dictionary when your build has one.
  • Furigana shows the reading of the kanji above them. It needs the Japanese dictionary that normal builds include. If your build lacks it, the setting says so and stays off.

Both are off by default. Chinese text without kana is left alone.

Translation

There are three kinds of translation:

  1. NetEase translations. Switch on NetEase translations to fetch NetEase’s own translation along with the lyrics and show it under each line.

  2. Online translation with your own key. Listen can send the lyrics to Microsoft Azure Translator or Google Cloud Translation. Set it up in Settings → Playback → Lyrics:

    1. Pick Translation provider: Microsoft Azure or Google Cloud.
    2. Paste your API key into Translation API key. You need your own account with that provider; Listen has no key of its own.
    3. Choose Translation language (31 languages, English by default).
    4. Press TRANSLATION in the lyrics view to translate the playing song. Turn on Automatic translation to translate every song’s lyrics as they load.
  3. Gemini (the AI DJ’s key). Pick Gemini as Translation provider. It needs no key of its own: it uses the Gemini key you set up for the AI DJ and its text model. Only lines with non-Latin letters are sent, numbered, so the translation always lands under the right line and whole English lines (common in K-pop) stay as they are, with no translation under them. English words inside a Korean line are kept. There is no romanisation. Each song’s translation is cached per language, so opening the song again needs no request; new lyrics for the song (another version) are translated afresh.

The whole text of the lyrics goes to the provider you chose in one request, with your key, and nothing else. The key is stored in Listen’s configuration file, so treat that file as private (see Privacy and security). The provider may charge for usage under your account.

Word meanings (Korean)

When the lyrics contain Korean and the AI DJ has a Gemini key, the lyrics controls show WORDS. Press it and every Korean word becomes clickable; click one to see its dictionary form (골랐다는 → 고르다), part of speech and a short meaning that fits the song, in the app language (German or English). All words of a song are looked up in one Gemini request the first time and cached, so later clicks open at once. Press WORDS again to make the lines clickable for seeking again.

Lute. Enter your vocab-hub address under Settings → Playback → Lyrics → vocab-hub address (empty = off). The word dialog then shows whether Lute knows the word (known, learning with its level, ignored, or not in Lute yet). Listen only reads your Lute words and never adds or changes a term; add new words in Lute itself.

Known words. With the vocab-hub set, WORDS also colours the Korean words by their Lute status: new words in green, words you are learning in light green, known and ignored words in the normal text colour. Next to WORDS the controls show how many of the song’s sung words you know (95 % known; every time a word is sung counts, ignored words are left out). Listen looks a word up as written, by its dictionary form and with particles cut off (사람들은 → 사람); words that are still unknown then are asked from the hub one by one, which finds conjugated forms the way Lute does (보낼게요 → 보내다). The percentage is the hub’s own count of the song (the same number the Lute Coverage extension shows). Lute changes show up within five minutes.

Exporting lyrics

EXPORT opens a preview of the file Listen would write. For synchronized lyrics you can keep Synchronized (.lrc) on (with an Offset (ms) written into the file) or switch it off to get plain text. The file is saved to your Downloads folder as Artist - Title.lrc or .txt, and the dialog shows the exact name. Word timings and translations are kept in the .lrc file.

Visualizer and Milkdrop

Listen draws a live picture of the music. The built-in visualizer is a spectrum analyzer with the same options as Feishin’s (audioMotion). On Linux you can switch to Milkdrop, which draws animated presets through libprojectM.

Where it appears

  • Full-screen player: the Visualizer tab. The Expand visualizer button there fills the whole window; Esc or Shrink visualizer goes back. See Full-screen player.
  • Right sidebar: a strip under the queue. It is on by default. Turn it on or off with Visualizer panel in Settings → Playback → Player sidebar panels (or Visualizer in queue in the Player options popover). You can also combine it with the lyrics panel and change the panel order there.
  • The player bar’s Visualizer button opens the full-screen player on the visualizer tab.

While the visualizer is not on screen, Listen does not capture or analyse audio.

What it listens to

The visualizer analyses the audio Listen itself plays. On Linux it records Listen’s own playback streams through PipeWire (pw-record and pw-dump must be installed, which they are with a standard PipeWire setup). Other programs and the AI DJ’s voice are not included, and the volume slider does not change the picture. On Windows it uses a loopback of the default output device, so it shows whatever that device plays, which includes other programs.

If the capture fails, the panel shows the reason instead of a picture. The visualizer shows nothing while you cast or use the server jukebox, because Listen’s own audio is silent then.

Spectrum options

Open Settings → Playback, find the Visualizer section and press Configure… next to Visualizer settings. The dialog Visualizer settings has the options below. Their names and ranges follow Feishin and audioMotion, and the dialog changes the picture live.

Presets. Select Preset picks a saved set of options. Four presets (Preset 1 to 4) come with Listen. To keep your own, type a name under Preset Name and press Save as Preset; Delete removes one of yours. Copy Configuration puts the current options on the clipboard as JSON and Paste Configuration applies options from the clipboard, so you can share setups with other Listen or Feishin users. Reset to default at the bottom restores the defaults (your saved presets stay).

General

OptionMeaning
Mode[0] discrete frequencies, [1] to [8] octave bands from 1/24th octave (240 bands) to a full octave (10 bands), or [10] line / area graph (default).
Line Width, Fill AlphaFor the graph mode.
Bar SpaceSpace between bars, for the bar modes.
Channel LayoutSingle, Dual-Combined, Dual-Horizontal or Dual-Vertical.
Max FPSFrame rate, 1 to 60; 0 uses 30.
Opacity0 to 1.

Colors: Color Mode (Gradient, Bar-Index, Bar-Level), Gradient (built-in gradients and your own), and for dual layouts Gradient Left, Gradient Right and Split Gradient.

FFT: FFT Size (1024 to 32768; default 16384) and Smoothing (0 to 0.95).

Frequency range and scaling: Minimum Frequency (20 to 50 Hz), Maximum Frequency (8000 to 22050 Hz) and Frequency Scale (Log, Linear, Bark, Mel).

Sensitivity: Weighting Filter (None, A, B, C, D, Z), Minimum Decibels (-120 to -60), Maximum Decibels (-40 to 0), Linear Amplitude with Linear Boost, and Volume (input gain, 0 to 4).

Peak behavior: Show Peaks (bar modes) or Peak Line (graph mode), Fade Peaks, Gravity, Peak Fade Time (ms) and Peak Hold Time (ms).

Radial spectrum: Radial, and with it Radial Invert, Spin Speed (-3 to 3 rpm) and Radius.

Reflex: Reflex Ratio, Reflex Alpha, Reflex Brightness, Reflex Fit and Mirror (Left, Off, Right).

Miscellaneous: for bar modes LED Bars (with True LEDs), Alpha Bars, Lumi Bars, Outline Bars, Round Bars, and Low Resolution (mode 0) or ANSI Bands; and for all modes Show Scale X, Note Labels, Show Scale Y and Show FPS.

Custom gradients. Under Custom Gradients, press Add Custom Gradient, name it, choose Vertical or Horizontal, and add colours as #rrggbb values with Add Color. Copy and Paste Gradient move a gradient through the clipboard. Your gradients then appear in the gradient choices.

Milkdrop (Linux)

Milkdrop is the classic music-visualizer format. Listen draws .milk presets with projectM. It is available on Linux only. Listen does not include projectM or any presets, so you need two things:

  1. libprojectM version 4 installed on your computer. Listen loads it when it starts; it is not needed to build or run Listen otherwise. Listen looks for libprojectM-4.so.4 in the system library paths, in /usr/lib64, and in /usr/local/lib64 and /usr/local/lib (where a build from source installs it).
  2. Milkdrop presets (.milk files) in a folder. By default that is presets inside the milkdrop folder of Listen’s data folder (on Linux ~/.local/share/listen/milkdrop/presets). Subfolders up to eight levels deep are read, so you can unpack a preset pack there as it comes. A different folder can be set in the settings.

To use it:

  1. Open Settings → Playback → Milkdrop. If libprojectM is missing, the row says “Milkdrop needs libprojectM 4” and the button stays disabled.
  2. Set Visualizer type to Milkdrop. The queue strip and the full-screen visualizer now show Milkdrop.
  3. Choose your folder in Preset folder (Browse…) and press Rescan after adding files. The row shows how many presets were found.

If the folder has no .milk files, the picture area says so and names the folder.

SettingDefaultMeaning
PresetSearch by name and pick a preset to show now.
Next presetSwitches now. The picture also has a next button.
Cycle presetsonSwitches to another preset on a timer.
Cycle time30 s (1 to 300)How long a preset stays.
Blend time2.5 s (0 to 10)How long a preset takes to fade into the next.
Random next presetonPick the next preset at random; off follows the list order.
Include all presetsonCycle through every preset; off limits it to the selected ones.
Selected presetsnoneAdd / remove current puts the preset on screen into your selection; Clear empties it.
Ignored presetsnoneIgnore current never shows the preset on screen again; Clear undoes that.
Max FPS0 (= 30)Frames per second; values are limited to 5 to 60.
Opacity100 %How strongly the picture shows.

Milkdrop renders on a hidden OpenGL context at 960 by 540 pixels and scales the picture to the available space. It draws from the same audio capture as the spectrum.

Music videos

For YouTube Music songs, Listen can show the music video in the full-screen player while the audio keeps playing as usual. This page explains the song/video switch and its limits.

Note: YouTube Music support is unofficial. Listen is not affiliated with, endorsed by or sponsored by Google or YouTube, and the feature may stop working whenever YouTube changes something. You use it with your own account and at your own risk. Listen does not download YouTube Music songs or videos for offline use. See YouTube Music.

Switching between song and video

The switch appears in the player bar only while a YouTube Music song is playing. It is a small video-camera button among the right-hand buttons:

  • Show video switches the video on.
  • Show song (the same button, now highlighted) switches back to the cover.

The switch is off by default. Turning it on opens the full-screen player and shows the video in place of the cover. The switch stays on for the following songs until you turn it off. In a narrow window, the phone-style full-screen player has the same switch in its bottom row.

How it behaves

  • The audio plays through the normal player. The video is a separate, silent picture, and the audio is the clock: the picture follows it, and if it drifts too far, it catches up by skipping ahead or restarting.
  • When the song plays from your own server (see YouTube Music), the video still shows: it follows the server’s audio as the clock. If both files have been analysed (including the YouTube Music one), Listen lines the video up with the server’s file by its beats and first sound; otherwise it assumes both start together.
  • Seeking, pausing, resuming and skipping to the next song move the video along.
  • The video of the next song is prepared in advance when possible, so it starts quickly after a song change.
  • The picture is rendered at 640 by 360 pixels and 30 frames per second, with black bars for other aspect ratios. This keeps the load low, and the picture is not saved anywhere.
  • For a song that has a separate music-video version, Listen shows the video; otherwise it shows the song’s own video.
  • If no video can be played, Listen shows a message (“No video: …”) and the cover stays.

Requirements and limits

  • Listen starts a second copy of mpv for the picture, and needs yt-dlp (a separately installed program, see Installation) to find the stream, as it does for the audio. If YouTube Music playback fails, update yt-dlp first.
  • The switch is not offered for songs from other servers.
  • It is turned off automatically when you start casting, and not offered while you cast.
  • The video is only drawn in the full-screen player, not in the small cover of the player bar.
  • A video uses noticeably more processor power and network traffic than audio alone.

Internet radio

Listen plays the internet radio stations stored on your Navidrome or other OpenSubsonic server. You can create, edit and delete stations from the app.

Availability

The Radio page is offered when the server you are browsing supports internet radio stations. Navidrome and other OpenSubsonic servers do; Jellyfin, YouTube Music and local folders do not. The Radio item is in the sidebar by default; if it is missing, check the sidebar items in Settings → General → Sidebar.

The stations are kept on the server, not in Listen, so they follow you to every app and computer that uses the same server account.

Playing a station

  1. Open Radio in the sidebar. Each station is a card with its name, stream address, home page address and, if the server has one, a picture.
  2. Click a card to play it. The card is highlighted, and the current stream title (“Now playing: Artist - Title”) appears on it when the station sends one.
  3. Click the playing station again, or press Stop in the player bar, to stop it.

While a station plays:

  • The player bar shows the station and the stream title. Only Stop and Play / Pause are available. There is no next, previous or seek, because a stream has no tracks.
  • Your queue is left untouched and waits. Press Play on a song or start something else to go back to music.
  • Starting a station ends casting to a device; the station plays on this computer.
  • If the stream fails, Listen shows a message with the station name and the reason.

Finding and sorting stations

The page header shows the number of stations. Use the search field to filter by name, the sort list to order by Name or ID and the arrow to reverse the order. The refresh button reloads the stations from the server.

Creating, editing and deleting stations

To add a station:

  1. Press Create station.
  2. Fill in Name and Stream URL. The address must start with http:// or https://.
  3. Optionally add a Home page URL.
  4. Press Create.

The pencil button on a card opens the same dialog to change the station (Save). The bin button deletes it after a confirmation; this cannot be undone. If you delete the station that is playing, it stops.

Tip: Use the direct stream address of the station (often ending in .mp3, .aac or .m3u8), not the address of its web page. The web page address belongs in Home page URL.

Casting to speakers and TVs

Listen can hand playback to a network speaker or TV that supports DLNA / UPnP (a “media renderer”). This page explains how devices are found, how to cast, how volume works and what does not work while you cast.

Turning it on

Casting is on by default. The switch is Cast to DLNA devices in Settings → Playback → Playback. When it is on, Listen searches your local network a few seconds after it starts, and again whenever you open the cast popover or press Refresh in it. When it is off, Listen sends no discovery messages and shows no cast button.

Discovery uses the standard SSDP multicast on the local network, so the device and the computer must be on the same network (not a guest network that isolates devices), and a firewall must let the device’s answers and its requests for the music through.

Casting a song

  1. Look for the cast button (a screen with a wave) among the right-hand buttons of the player bar. It only appears once at least one device has been found.
  2. Click it. The popover Cast to a device lists This computer and the devices found, with their model names.
  3. Click a device. It shows “Connecting…” and then a check mark. A message says “Casting to” the device’s name.

If your device is not listed, make sure it is switched on and on the same network, then press Refresh.

If a song was playing, it continues on the device from the same position. If nothing played, the device gets the playing song when you press Play. The queue stays in Listen; the device plays the songs one after another as the queue advances. Pause, stop, seek, next and previous in the player bar control the device.

To go back, open the popover and choose This computer. A song that was playing continues here at the same position.

Volume

While you cast, the volume slider and the mute button in the player bar control the device’s volume. The speaker icon turns accent-coloured, the slider’s tooltip names the device and the mute button’s tooltip reads “Mute the device”. When you stop casting, the local volume comes back as it was. A device that offers no volume control keeps its own level.

How the music reaches the device

The device fetches each song itself. For a plain http:// address, Listen simply passes the address on. For local files, and for streams that use HTTPS or need request headers, Listen starts a small web server on your computer, bound to the network address that reaches the device. The device then loads the audio from your computer. Each song gets an unguessable address, and Listen never passes your account’s cookies on. The server stops when you stop casting.

The device shows the title, artist and album of the song.

What does not work while casting

Everything that depends on this computer’s audio engine is off:

  • DJ transitions and the AI DJ’s voice are off. The Auto-DJ still adds songs.
  • The equalizer, compressor, ReplayGain, playback speed, pitch and fades, because mpv, which applies them, rests while you cast. See Sound.
  • The visualizer has no audio to show.
  • The song/video switch for music videos is off and is switched off if it was on.
  • Songs are loaded one by one, so there can be a short gap between songs instead of gapless playback.
  • Whether a particular file plays depends on the device: renderers differ in the formats they support. If a device cannot play a song, Listen shows “could not play this song” with the reason.
  • Starting an internet radio station ends casting; the station plays on this computer.

If the device stops answering (five failed checks in a row), Listen says it lost the connection and continues playing on this computer.

The cast popover also notes these limits while a device is in use.

Song analysis

Listen can listen to your songs once and remember what it heard: where the beats and bars are, how fast the song is, which key it is in, how loud and energetic it is and how it is built. The DJ transitions and the AI DJ use these measurements. This page explains what is measured, where the results are kept and how to control the background work.

Analysis is on by default for Navidrome (OpenSubsonic) songs. You can ignore it completely if you do not use the DJ features: it never changes your files and it only runs in the background.

What is measured

For every analysed song Listen stores:

  • Beats and downbeats. The position of every beat and which beat starts a bar. This is what makes beat-matched blends possible.
  • Tempo. Beats per minute, with a confidence value. If your server provides a BPM tag, Listen uses it only as a hint to decide between half and double tempo.
  • Key. The musical key, shown in the Camelot notation used by DJs (for example 8A or 11B). Keys that are neighbours on the wheel sound good together.
  • Sections. Intro, body, breakdown, build, drop and outro, counted in bars, plus phrase length (4, 8 or 16 bars).
  • Energy. Loudness, bass level, brightness and how likely a lead vocal is, one value per bar. From these Listen derives an overall energy, danceability and brightness. It also finds how many bars at the start and end of a song have no lead vocal, because those are the best places to blend.
  • Loudness. Integrated loudness and loudness range, and the first and last moment where the song is actually audible.
  • Timbre. A short vector that describes the sound of the song, used to judge how similar two songs are.

Songs without a steady beat (ambient, live recordings, strong tempo drift) get no beat grid. They are still analysed, but they are joined with plain fades.

Songs longer than 30 minutes are skipped.

Which songs are analysed

SourceAnalysed
Navidrome / OpenSubsonicYes, queue first and then the whole library
YouTube MusicOnly if you switch it on, see below
Jellyfin, local folders, internet radioNo

Songs from sources that are not analysed are never beat-mixed. They play as usual.

The beat model

To find beats and downbeats Listen uses a small neural network called Beat This! (MIT licence, from the Johannes Kepler University Linz). The two model files are about 11 MB in total and are downloaded once, the first time analysis runs. They are checked against a fixed checksum and then stored in the models folder inside Listen’s cache folder (see Files and folders). Nothing else is downloaded and no song data is sent anywhere.

If the download fails (for example because you are offline), Listen falls back to a simpler built-in beat tracker and tries to download the model again the next time it starts. The built-in tracker is less accurate, especially above about 140 BPM.

The status line (see below) shows which one is in use: Beats: Beat This! or Beats: built-in tracker.

The singing-voice detector (optional)

Where the singing is decides where a DJ transition can start and end without talking over a sung line. Without extra files Listen estimates it from the sound (centred, tonal sound in the voice range that changes like syllables). That estimate is rough: synth leads and chants can look like a voice, and a quiet first verse can be missed. Synced lyrics, when there are any, correct it (see Transitions).

For songs without synced lyrics you can download a small neural network that listens for singing: the singing-voice detector of the DJustify research project (Hsu et al., 2026), trained on the Jamendo corpus. Its code is MIT licensed, but its weights are licensed CC BY-NC 4.0: free for non-commercial use only. That is why Listen does not ship it and you choose to download it: Settings → Playback → DJ transitions & song analysis → Singing-voice detector → Download. The file (2 MB) comes straight from the authors’ repository at a fixed version, is checked against a fixed checksum and is stored in the models folder of Listen’s data folder, so clearing caches doesn’t remove it. Remove deletes it again.

With the detector, every song analysed from then on gets its vocal curve and its instrumental intro and outro from the detector (it adds about a second per song). Songs that were analysed without it are analysed again in the background, Navidrome and local songs only: YouTube Music songs keep their analysis, because fetching them again would use up YouTube’s request budget. The status line says vocals: singing-voice detector or vocals: built-in heuristic; it switches as soon as Download or Remove finishes. On three songs with synced lyrics, the detector’s vocal curve agreed with the lyrics better than the estimate (correlation 0.73 against 0.55; the start of the singing within 3 s instead of 10 s).

How the work is scheduled

Analysis runs in a separate helper process with low priority, so it should not disturb playback. The helper stops by itself after 30 seconds without work and is started again when needed.

Songs are analysed in this order:

  1. The song that is playing and the next one.
  2. The rest of the queue (the next 12 songs).
  3. YouTube Music only: when Auto-DJ or the AI DJ is on, songs similar to the current one, so the next pick can be ordered by flow (Navidrome songs are covered by step 4).
  4. The whole Navidrome library, a little at a time in the background. This is the “crawl”. Listen lists your library first and then works through it.

Queue work always goes first, so a song you are about to hear is analysed before a song you might hear next month. Library work pauses while a DJ transition is running, so the mix gets all the processor time it needs.

A 3.5 minute song takes roughly 2 to 3 seconds on a current desktop processor. A library of 10,000 songs therefore needs several hours in the background. Songs are analysed only once: the results are kept, and if two computers share the same folder they split the work (see Sharing between computers).

If a later version of Listen improves the analysis, old results are used until the song has been analysed again, and the new analysis runs at low priority.

Battery

On a laptop that is running on battery, library analysis pauses. Work for the queue (and for YouTube Music DJ candidates) still runs, because a transition may depend on it. To also analyse the library on battery, turn on Also on battery.

Note: Detecting battery power works on Linux. On Windows the library crawl is not paused on battery.

Threads

Beat detection uses several processor threads. By default Listen uses a quarter of your cores (at least one). To change that, set threads in the [analysis] section of the settings file (see Files and folders). 0 means automatic; any other number is limited to the number of cores you have. The change takes effect after a restart. There is no switch for it in the settings window.

Settings

All switches are in Settings → Playback → DJ transitions & song analysis.

SettingDefaultWhat it does
Analyse songsOnMaster switch. When off, nothing is analysed and the DJs work without measurements.
YouTube Music songsOffAlso analyse YouTube Music songs. Needs an analysis folder.
Whole libraryOnWork through the whole Navidrome library in the background. The queue always comes first. When off, only the songs in the queue are analysed (and, for YouTube Music, the DJ candidates).
Also on batteryOffKeep analysing the library when the laptop is unplugged.
Analysis folderListen’s data folderWhere the results are stored. Can be a synced folder shared between computers.
Singing-voice detectorNot downloadedDownload fetches the optional detector (2 MB, CC BY-NC 4.0, see above); Remove deletes it.

Below the first switches there is a status line, described next.

The status line

The grey text under YouTube Music songs tells you what is going on. It can contain:

  • N songs analysed, and in brackets how many each computer contributed when a folder is shared.
  • library N songs, the size of the library found so far, with (listing...) while the library is still being listed.
  • N waiting, the number of songs in line.
  • A reason for waiting in brackets: paused during a DJ transition, library analysis is off or paused on battery.
  • Now: the song being analysed.
  • Beats: the beat source, vocals: where the vocal curve comes from, and this machine: the name that identifies this computer in the shared folder.
  • An error, for example when the analysis folder cannot be written.
  • If you have a YouTube Music account: YouTube Music: analysed on demand (queue and DJ candidates) or YouTube Music: not analysed.

It shows Off. when Analyse songs is off and Starting… for a moment after start.

The analysis folder

By default the results are kept in a folder called analysis inside Listen’s data folder (see Files and folders). To use another folder, type its path into Analysis folder and press Save, or press Choose… and pick it. Leaving the field empty returns to the default. Changing the folder restarts the analysis; results in the old folder are not moved, so copy them over first if you want to keep them.

Inside the folder Listen creates v1/<computer name>/000001.jsonl, 000002.jsonl and so on. These are plain text files with one song per line, including the artist and title so you can recognise them. They contain only measurements, never audio.

Sharing the results between computers

Analysing a big library takes time, so it is worth doing only once. If you point Analysis folder on every computer at the same synced folder (for example a folder in Nextcloud, Syncthing or any other sync tool), then:

  • every computer reads the results of all the others;
  • every computer writes only into its own sub-folder, so two computers never write to the same file and sync conflicts are avoided;
  • songs that another computer has already analysed are not analysed again;
  • the status line shows how many songs each computer contributed.

Results are matched by song and file, not by server address, so it also works when the computers reach the same server under different addresses. If a song’s file is replaced on the server (for example re-encoded), it is analysed again.

Tip: Let the sync tool finish its first sync before you start Listen on the second computer, otherwise both computers analyse the same songs in the meantime.

YouTube Music songs

Note: YouTube Music support in Listen is unofficial and not affiliated with Google or YouTube. See YouTube Music. Listen does not download YouTube Music songs for offline use.

YouTube Music songs can be beat-mixed too, but they need a measurement like any other song. This is off by default. To turn it on:

  1. Choose an analysis folder first (see above). The switch stays off while the folder is empty.
  2. Turn on YouTube Music songs.

When a YouTube Music song is wanted, Listen fetches a temporary copy of the audio, measures it, and then keeps only the measurements. The audio itself is not saved as a library.

YouTube Music songs are analysed only on demand: the playing song, the queue and a limited number of candidates for the DJ (at most 20 per playing song). The whole YouTube Music library is never crawled, and requests to YouTube are limited on purpose. If a request is turned down, Listen tries again later. You use this at your own risk, like the rest of the YouTube Music support.

Turning analysis off

Turn off Analyse songs. Existing results stay in the folder and are used again if you turn it back on. Without analysis the Auto-DJ and AI DJ still work, but songs are never beat-matched; they follow each other with the normal gapless playback.

You can also read progress from scripts: the MCP tool get_analysis_status returns the same information as the status line.

DJ transitions

With DJ transitions on, Listen mixes songs into each other like a DJ instead of simply playing one after the other. It matches the beat, lines the songs up bar by bar, and moves the bass and the tempo so the change is hard to notice. This page explains what happens and what each setting does.

Transitions use the measurements described in Song analysis. Without analysed songs nothing is mixed.

When songs are mixed

A transition is made only when all of this is true:

  • DJ transitions is on.
  • Both songs come from Navidrome (OpenSubsonic) or YouTube Music (with analysis switched on for it). Jellyfin, local files and radio are never mixed.
  • A DJ chose the songs: the Auto-DJ or the AI DJ added the next song, or you added it with Add to queue while a DJ is on and Mix queued songs is on.
  • The two songs are not consecutive tracks of the same album (same disc, track numbers one apart). Albums stay gapless.
  • Both songs have been analysed.

Songs you start yourself by playing an album or playlist always play gapless, with no mixing. If a mix cannot be prepared in time, or you skip, seek or pause during the lead-up, Listen simply falls back to gapless playback.

What a transition sounds like

Listen looks at both songs and picks the best way to join them. It prefers to start the blend on a phrase boundary, where the outgoing song is instrumental (or at least has no singer at the same time as the incoming song).

KindWhat happens
Long blendA beat-matched crossfade over 8 or 16 bars (see Long blends), used where both songs have instrumental parts. With Bass swap on, the bass of the outgoing song is cut halfway through, exactly on a downbeat, while the incoming bass comes in, so the two basslines never play together.
Short blendA beat-matched crossfade of a few bars, placed so the vocals do not overlap.
Filter-outThe outgoing song is filtered away (its low end disappears first) while the next one starts on a downbeat.
Echo-outThe last beat of a phrase of the outgoing song is repeated four times, each repeat half as loud and thinner, while the next song starts on the downbeat right after. The two songs never play their own sound at the same time, so the tempos need not match and the voices don’t clash. Used when both edges are sung, or the tempos are too far apart for a blend, and the outgoing song ends a phrase loudly or with a sung line. A bridge song is tried first (see Bridge songs), and a song that came in with an echo-out never leaves with one: its way out is a cut, a blend or a fade.
CutA hard switch on a phrase downbeat (with a few milliseconds of fade so it doesn’t click), each song at its own tempo. Used in the same cases as an echo-out when the bar before is quiet.
FadeA plain crossfade, used when one song has no steady beat, or while the AI DJ talks over the join.
GaplessNo mixing at all.

Lyrics show where the singing is

The song analysis guesses from the sound where a singer is, and it often hears a voice in a synth lead or a chant. Synced lyrics are much more exact: each line has a start time, and the gap to the next line shows where the singing stops. So while a song plays and while it is next, Listen looks up its synced lyrics the same way as for the lyrics view (the server’s lyrics first, then the lyric providers if Fetch lyrics is on) and uses them for the transition:

  • Where the singing is. Bars without a sung line count as instrumental, even if the sound analysis thought otherwise. That finds the short vocal gaps that pop and K-pop songs have, such as rap breaks, dance breaks and post-chorus hooks, so more pairs get a real blend and fewer a filter-out.
  • Where a line ends. In the last 40 % of a song, a mix may start right after a sung line when a gap follows, not only in the outro. A mix that would stop the outgoing song in the middle of a line is avoided.
  • Where the chorus is. The block of lines that repeats most is the chorus. A blend that ends right where the next song’s singing or chorus starts is preferred, and the next song may skip part of its intro for it (at most within its first 40 % or 90 seconds).

Cutting a song short or skipping an intro costs the plan points for every second, so Listen only does it when the join is clearly better. Transitions may skip parts of songs (Settings → DJ transitions) limits this: Free (the default) allows it as described, Short allows at most 16 seconds on either side, and Never keeps every mix in the outgoing song’s outro and starts the next song at its first beat. Lyrics are not used when they do not fit the song: when they run past its end, or when the sound analysis hears singing mostly where the lyrics are silent, or the lyrics fit much better a few bars earlier or later (an offset, or the lyrics of another version). Plain (unsynced) lyrics are not used. A transition is planned at once with what is known; if the lyrics arrive later but well before the mix, it is planned again.

While both songs play, Listen keeps the overall loudness steady: the sum of the two follows a straight line from the level of the outgoing song just before the mix to the level of the next song just after it. It knows how loud each part of a song is from the song analysis, so a blend over a quiet outro is lifted a little (at most 3 dB) and two loud choruses together are turned down (at most 6 dB). With Volume levelling on, each song’s own gain is taken into account. Echo-outs and cuts have no overlap and are left as they are.

Before a transition is armed, Listen plays it through once on the song analysis (no audio is needed, and it takes well under a millisecond). It rejects the plan if the mix would fall more than 1.5 LU below the quieter song or rise more than 1.5 LU above the louder one. Because the analysis is a little rougher than the audio, a predicted drop already fails from 0.9 LU. It also rejects it if both singers would be clearly heard together for more than a second, or if the outgoing song would stop in the middle of a sung line (this last check is only made when synced lyrics show where the lines end). A rejected plan gives way to the next best option, and the plain fade comes last. If no option passes, the one with the smallest problem plays. Rejected plans are written to the log with the reason.

For a beat-matched blend the two songs must run at the same speed. Listen speeds one or both songs up or down by a few percent without changing the pitch. With Tempo ramps on, the speed glides smoothly during the blend and returns to the natural speed of the new song afterwards. With it off, the tempo is matched for the whole blend at once, which can be heard on large differences.

Songs whose tempo is double or half of the other (for example 70 and 140 BPM) are matched at that ratio instead of being sped up a lot.

The speeds are taken from the bars that actually overlap, not from each song’s average tempo. Many songs drift a little (a slower intro, a live drummer), and a speed set from the average would let the beats slide apart by tens of milliseconds during a long blend. When the incoming song speeds up or slows down inside the blend, its speed glides along with it so the beats stay together, also when one of the songs slows down and picks up again within the blend (the speed then follows a smooth curve, adjusted bar by bar). A mix point whose beats still wouldn’t line up is passed over for a better one, or the songs join with an echo-out or a cut.

Note: Tempo changes use the rubberband library inside mpv. If your mpv was built without it, Listen uses a different method, which works but can make the beat wobble slightly while a song is not at its natural speed.

Bridge songs

Some pairs a DJ picked do not join well: the tempos are too far apart to beat-match, the keys clash, or the two songs simply sound very different. A club DJ solves this with a bridge track: a record that sits between the two, keeps the feel of the first and leads towards the second, so each step stays small.

With Bridge songs on, Listen does the same with a song that has already been analysed:

  1. When the next song is far from the current one (no beat-matched join, a tempo gap of more than 4 %, clashing keys, or a large difference in sound), Listen looks for a bridge among your analysed songs: first the ones the DJs were recently offered, then your listening history, then every other analysed YouTube Music song. Only a few songs have a mostly instrumental stretch at a tempo between the two, so the whole collection is searched. Songs in the queue and songs played this session are not used.
  2. The bridge must be closer to both songs than they are to each other, and both joins, into the bridge and out of it, must be beat-matched blends. When the two songs could only be joined with an echo-out, a cut or a fade, a bridge that is no further from either song than they are from each other is enough: a beat-matched way through a third song is preferred to those.
  3. The bridge must belong to the music the two songs are from: between two K-pop songs it is a Korean pop song, never an American rap record that merely blends well. When the two songs are from different scenes, the bridge comes from one of them. Listen knows a song’s scene from its Describe it tags (genre, country and language), the song’s own genres, the artist’s other songs, or a Korean or Japanese title; songs it can’t place are also compared by their sound (the Describe it audio embedding). The scene includes the era (the decade, from the tags, the release year, the artist’s other songs or the songs that sound closest): a bridge between two songs of the 2020s comes from the 2010s or the 2020s, never from the 1980s or 1990s. A song without a known era fits only when its language and genre both match. The same artist always fits, and so does an artist you have heard right next to one of the songs, when nothing else is known and both or neither have a known era. A song whose scene is unknown is not used when the two songs’ scenes are known: no bridge is better than a wrong one. Among the songs that fit, the closest scene is preferred.
  4. Only a short part of the bridge plays: 24 bars (about 45 seconds at 125 BPM) that start on a phrase and have no singing where they are blended, usually an instrumental groove, a break or a long intro. Listen blends into it with a short blend of up to 8 bars, glides it back to its own tempo, lets it play alone for a few bars, and blends out of it into the next song.

The bridge shows in the queue with the tag Bridge. It does not count as played: it is not scrobbled and not added to the listening history. If its mix cannot be prepared, the bridge is removed and the two songs join as before; if nothing mixes out of it, the next song starts when its part ends.

How often to bridge sets the share of far-apart pairs that get a bridge, so it stays an occasional move rather than a pattern. It applies only to pairs that could still be blended directly; a pair that would otherwise get an echo-out, a cut or a fade tries a bridge every time.

Order by flow

When a DJ picks several songs, Order by flow arranges them so that each song follows from the one before: similar tempo, neighbouring keys and a sensible energy curve, and without repeating the same artist too soon. The Auto-DJ and the AI DJ both use this. Songs without analysis are placed by the server’s own similarity order.

Order for smooth mixing

The same idea works on a whole playlist or the queue. Play in smooth order (right-click a playlist), Order for smooth mixing (right-click a queue row, or the button in a playlist’s edit mode) put all analysed songs into an order where tempo, key, energy and sound change as little as possible from one song to the next, and the same artist does not play twice in a row. The first song stays first (in the queue: the playing song). Songs without analysis keep their order and go to the end. A playlist on the server only changes when you press Save and replace in edit mode.

The order is found in a few milliseconds even for a few hundred songs: Listen starts with the closest next song each time and then keeps reversing stretches and moving single songs while that makes the whole run smoother.

Settings

Everything is in Settings → Playback → DJ transitions & song analysis.

SettingDefaultRangeWhat it does
DJ transitionsOnon/offMaster switch for mixing.
Order by flowOnon/offPick songs whose tempo, key and energy follow on from the current one.
Largest tempo change6 %2 to 8 %The biggest speed difference Listen accepts for a beat-matched blend. Beyond this the songs join with an echo-out or a cut instead. Smaller values sound more natural and mix fewer songs.
Long blends16 bars8 or 16Length of a blend over instrumental intros and outros. At 120 BPM, 16 bars take 32 seconds and 8 bars take 16.
Transition edgesSmartAlways, Instrumental only, SmartWhether vocals at the end of the outgoing song or the start of the incoming one may be blended over. Instrumental only needs instrumental edges, otherwise the songs get a short blend or a filter fade. Always never lets vocals stop a blend. Smart allows it for club and electronic genres (UK garage, house, techno, trance, drum and bass, dubstep, grime, amapiano and similar), where vocal samples over the beat are normal, and keeps the strict rule for everything else. The outgoing song’s end is relaxed by its own genre, the incoming song’s start by its own. Songs without a genre tag, including YouTube Music songs, count as non-club. Tempo, key and beat checks apply in every mode.
Transitions may skip parts of songsFreeNever, Short, FreeHow much a transition may leave out to land on a cleaner mix point: the end of the outgoing song after its last sung line or from a breakdown, and the next song’s intro up to its verse or chorus, or up to its first phrase. Free allows it wherever the join is clearly better, Short at most 16 seconds of either, Never mixes only in the outro and starts the next song at its first beat.
Tempo rampsOnon/offGlide the tempo between songs instead of jumping.
Bass swapOnon/offSwap the basslines on a downbeat so only one plays at a time.
Mix queued songsOnon/offAlso mix into songs you added with Add to queue while a DJ is on.
Bridge songsOnon/offPut a short part of an analysed song between two songs that are far apart and mix through it (see Bridge songs).
How often to bridge50 %10 to 100 %Share of far-apart pairs that get a bridge when one fits. Pairs that cannot be beat-matched always try one.

One more value has no switch in the window. Set it in the [mixing] section of the settings file (see Files and folders) or with the set_settings MCP tool:

KeyDefaultRangeWhat it does
fallback_fade_secs4.03 to 6 secondsLength of the plain fade used when songs cannot be beat-matched and no echo-out or cut fits.

Mixing with the AI DJ

The AI DJ knows how each candidate song would be mixed in after the current one, and it can talk over a blend. When a spoken break is planned over the end of a song or the start of the next one, Listen allows a longer blend to leave room for the voice, and it keeps the voice shorter than the instrumental intro so the host never talks over a singer.

Troubleshooting

  • Songs are not mixed. Check that Analyse songs is on, that the songs have been analysed (see the status line), that Auto-DJ or the AI DJ is on, and that the songs come from Navidrome or YouTube Music. Consecutive tracks of an album are always gapless.
  • Many echo-outs, few beat-matched blends. Raise Largest tempo change: songs whose tempos are too far apart are joined with an echo-out or a cut. Songs without a steady beat are faded.
  • A song was skipped for mixing right after you started it. A mix needs about 5 seconds of lead time. Songs started late are played gapless.
  • A song ended earlier than usual, or the next one started after its intro. The lyrics showed a cleaner place to mix (see Lyrics show where the singing is). listen --check-mix A B --lyrics-a A.lrc --lyrics-b B.lrc shows how a pair is planned with given lyrics.
  • Why was this transition chosen? The log lists every plan that was rejected before it (rejected … loudness dip, vocals clash, cuts a sung line). listen --check-mix A B --render out.wav shows the same check for a pair and measures the rendered preview’s loudness hole and bump.
  • Different tempo after the mix. That is the intended tempo ramp. If you dislike it, turn off Tempo ramps or lower Largest tempo change.

How the engine works internally is described in DJ transitions internals.

AI DJ

The AI DJ picks sets of songs from your library that fit the mood of the song you started it on, and talks between the sets like a radio host. It uses Google’s Gemini models with your own API key. This page explains how to set it up, what every option does and what is sent to Google. To get a key, see Creating a Gemini API key.

The AI DJ is optional and off by default. It replaces the Auto-DJ while it is on, and it works together with DJ transitions and song analysis.

Turn it on

  1. Create a Gemini API key (instructions).
  2. Open Settings → Playback → AI DJ.
  3. Paste the key into Gemini API key and press Save. Listen plays a short sample of the current persona’s voice to check that the key works. The result appears in a status line below the options (for example “Late-Night works.”).
  4. Switch Enabled on. If there is no key yet, Listen refuses and tells you to add one. You can also tick Turn on the AI DJ in the setup wizard.
  5. Start any song and choose AI DJ with the play-mode button in the player bar.

The song you start from becomes the seed: the mood the DJ tries to keep. Songs you add to the queue yourself while the DJ is on steer it too. If you want a new mood, start another song and switch the DJ on again.

What it does

While the AI DJ is on, Listen plans one set at a time. When the last song of a set starts, it asks Gemini for the next set and a line to say. Gemini chooses the songs from a list of about 40 candidates taken from your music server: songs similar to the seed, some similar to the current song, songs similar to your latest manual picks and a few random ones. Songs that played this session, are in the queue or were picked recently are left out.

With the listening history on, up to 5 of the candidates come from it: songs from your heavy rotation of the last 30 days (not ones played today) and favourites you have not played for two months, the ones that flow best from the current song. Each candidate also tells the DJ what you know of it: how often you played it and when you last did, or that it is new to you (and whether its artist is). The DJ mixes familiar songs with new ones, and when it talks before a set that has a song new to you, it introduces one of them with a short line about it. It is told to state only facts it is sure of and otherwise to talk about the sound. “New to you” is only used once the history covers at least two weeks and 100 plays, so a fresh install does not call every song new. These tags go to Gemini with the song titles (see Privacy).

With every set the DJ also writes a short note per song (at most 80 characters) on why it fits right now. Hold the pointer over the AI tag of a song in the queue to read it; the note of the playing song is shown in the full-screen player.

The break is spoken with a voice model and placed at random where it fits:

  • between songs, in the silence after the current song;
  • over the end of the current song, which is turned down while the host talks;
  • over the start of the first song of the new set;
  • across the change, starting over the end of one song and finishing over the start of the next.

The music is turned down while the voice speaks and back up afterwards. Breaks are short, at most 10 to 20 seconds of speech.

Tell the DJ

While the AI DJ is on, the queue panel (and the Now Playing page) shows a Tell the DJ… box with quick requests under it: Calmer, More energy, More new songs, Only favourites, Focus, Korean only and No ballads. Click a chip to ask for it and click it again to take it back, or type your own request (“more 2010s girl groups”) and press Enter; typed requests show as chips with an × to remove them.

A new request takes effect at once: the songs the DJ queued that have not started yet are taken out and it plans a new set with the request. The song playing now plays on (a transition already planned into the next DJ song keeps that song, and the new set follows it), and songs you queued yourself stay; while some of those are still queued, the new set comes after them. In its next break the DJ briefly says it heard you. Asking for a request that is already active changes nothing and costs no Gemini request.

Requests stay active, also after a restart, until you remove them, and every later set follows them. Calmer and More energy exclude each other, and so do More new songs and Only favourites. With analysed songs the requests also narrow the candidate list before Gemini sees it: Calmer keeps only songs with less energy than the ones it replaced (More energy: more), even when that leaves just one or two for a shorter set; only when no candidate has less (more) energy it keeps the eight calmest (most energetic), No ballads drops slow, soft songs, Focus drops the loudest ones, Only favourites keeps songs you have played at least three times (and takes more of them from your history) and More new songs keeps mostly songs new to you. Korean only is left to the DJ, because titles don’t show the language reliably.

How it uses the analysis

If songs are analysed, the DJ knows more than titles. Each candidate is described with tempo, key and energy, plus a short conclusion of how it follows the current song (keys compatible or clashing, tempo close or a big jump, energy up or down), and the DJ is told how the mix engine would bring it in after the current song. The candidate list is ordered by how well the songs flow from the current one, so the DJ is offered songs that mix well. The DJ can also mention its mixes, and it keeps a talk-over shorter than the instrumental intro of the next song so that it never talks over a singer.

Without analysis the DJ still works; it then relies on the server’s own similarity and the server’s BPM tag.

Where it works

The AI DJ picks songs from the server that the seed song belongs to. Beat-matched transitions between the picks need analysis, which exists for Navidrome and (if switched on) YouTube Music songs. When a speech clip is planned, it is not used while you cast to a TV or speaker over DLNA; the lines are then shown as text.

Personas

A persona sets the character, tone and voice of the host. Pick one in Persona and press Preview to hear it. The preview is cached, so after the first time it costs nothing.

PersonaHostsStyle
Late-Night (Puck)One hostRelaxed late-night host with dry wit. Short, never cheesy. The default.
Morning Show (Fenrir)One hostUpbeat morning-show energy.
Calm (Kore)One hostCalm and minimal: one or two sentences, with music knowledge. Only says facts it is sure about.
Hamburg Duo (Hauke & Merle)Two hostsAn energetic morning-show pair. Merle chimes in on roughly every other break and the two talk to each other. When the show is in German it has a light northern German flavour.

The voices are Gemini’s built-in voices. Two-host breaks are spoken in a single request.

Settings

All options are in Settings → Playback → AI DJ.

SettingDefaultRangeWhat it does
EnabledOffon/offTurns the AI DJ on.
Gemini API keyemptySaved in the system keyring. Paste a new one to replace it, save an empty field to remove it.
PersonaLate-Night4 personasWho talks. Preview plays a sample.
Voice modelFlash-Lite TTS (fast)2 modelsSee below.
Songs per setup to 52 to 8The DJ picks 2 up to this many songs between its breaks.
Talk afterevery set1 to 5Talk after every set, or only after every 2nd, 3rd and so on. Saves speech quota. The DJ keeps picking songs in the sets in between.
Spoken breaks per day150 to 50The most breaks Listen asks to be spoken per day. After that the lines are shown as text.
Voice volume0 dB-12 to +12 dBLoudness of the voice relative to the default level, which suits music with ReplayGain.
LocationemptyWhere the show airs, for example Kiel. The hosts mention it now and then. Empty means no home town.
PronunciationemptyHow the voice should say the place name if it gets it wrong.
LanguageSame as the appapp languagesThe language the hosts speak. Song titles stay in their own language.
Details for the DJemptyAnything the hosts should know: your name, what you like, topics to avoid.

Models

Listen uses two Gemini models. They are chosen for the free tier:

  • Text model, gemini-3.5-flash-lite: picks the songs and writes the lines.
  • Voice model, one of:
    • Flash-Lite TTS (fast), gemini-3.8-flash-lite-tts, the default.
    • Flash TTS (best voice acting), gemini-3.8-flash-tts, with more expressive delivery.

The text model can also be changed in the [ai_dj] section of the settings file (text_model). Use a model name that your key can access.

Location and Pronunciation

Type a town or region into Location, for example Kiel or Kiel, Germany. The hosts will mention it occasionally. Text after a comma or bracket is only context; for Pronunciation, Listen uses the first part (the place name). If the voice says the name wrongly, write it the way it should sound in Pronunciation, for example Keel, and use Preview to test. The hint is passed to the voice model for lines that contain the place name.

Details for the DJ

A line of free text, for example Call me Sam. I love 90s R&B. No weather talk. It is sent to Gemini with every break, so keep it short and do not put anything in it that you do not want to send to Google.

Quotas and the text fallback

The free tier of the Gemini API has daily and per-minute limits, and the speech models have a small daily allowance. Listen sets no limit of its own: every break is voiced until Google says the quota is used up.

  • Spoken breaks in the settings shows how many breaks were voiced today. A day is counted like Google counts it, resetting at midnight Pacific time.
  • Talk after lets the DJ skip talking after some sets.
  • The Preview counts as one spoken break the first time you play a persona with a model.
  • When Google says the daily speech quota is used up, the DJ keeps picking songs and shows its lines as text on screen. It tries speech again after an hour. Saving a new key clears this state.
  • If the limit is only per-minute, Listen waits briefly and tries once more.

If the text model fails or its limit is reached, similar songs fill in (as if the Auto-DJ were on) and a message tells you that the AI DJ is unavailable. Listen then waits before trying again, a little longer after each failure, up to an hour. A rejected key shows a warning that points you to Settings → AI DJ.

Playback never waits for the DJ: if the answer is late, the music simply continues.

If the player ever ends up idle while songs are still queued — a song that will not load, a break whose clip had nothing behind it — a check every five seconds starts the next queued song, so the music picks up again on its own instead of standing still until you press play.

Privacy and data sent to Google

Listen has no server of its own. Requests go from your computer straight to Google under your own key.

What is sent:

  • Song titles and artists the DJ chooses from, plus year and up to two genres where known.
  • Short analysis summaries (tempo, key, energy) and a description of how songs were mixed.
  • Which songs you skipped and which you queued yourself.
  • Your requests from Tell the DJ.
  • The DJ’s own previous lines.
  • Your Persona, Language, Location, Pronunciation and Details for the DJ.
  • The lines to be spoken (to the voice model).
  • Your API key, as a request header.

What is not sent: audio of your songs, your server address and sign-in, file names or paths, and the rest of your library.

Outside the EU, UK and Switzerland, Google may use free-tier requests to improve its products, and human reviewers may read them. With billing enabled on the key’s project, requests are not used that way. Details are in Google’s Gemini API terms, which require you to be 18 or older. The generated clips are stored briefly in Listen’s cache folder and removed when Listen starts the next time.

The key is kept in the system keyring. The environment variable LISTEN_GEMINI_API_KEY, if set, takes precedence over the saved key, which is handy for testing.

Troubleshooting

ProblemWhat to do
Switching on says to add a keyPaste the key into Gemini API key and press Save.
“the Gemini API key was rejected”The key is wrong, restricted or deleted. Create a new one and save it.
Status line says “Didn’t work” with a quota messageYou hit Google’s limit. Wait, lower Spoken breaks per day, set Talk after to a higher number or try again tomorrow.
Lines appear as text and nothing is spokenThe daily speech quota or Spoken breaks per day is used up, or you are casting over DLNA.
Songs repeat or feel offStart the DJ from a song that fits the mood you want. The seed decides the mood.
“AI DJ unavailable; similar songs fill in”A network or Google error. The Auto-DJ keeps the music going and the DJ retries later.
Place name sounds wrongFill Pronunciation and test with Preview.
The voice is too quiet or loudAdjust Voice volume.
The DJ never mixes songsMixing needs analysed Navidrome or YouTube Music songs, see DJ transitions.

Creating a Gemini API key

The AI DJ talks to Google’s Gemini models and needs an API key from you. Listen ships no key and has no server of its own. This page walks you through creating a key for free, putting it into Listen and looking after it.

You need a Google account and you must be 18 or older, because Google’s Gemini API terms require it.

Note: Google changes the AI Studio website from time to time. Button names may differ slightly from the ones below.

Create the key

  1. Open Google AI Studio, API keys and sign in with your Google account.
  2. If this is your first visit, read and accept the terms.
  3. Press Create API key.
  4. Choose a Google Cloud project:
    • If you have never used Google Cloud, pick the option to create the key in a new project. AI Studio creates a project for you, and that is all you need.
    • If you already have projects, you can pick one from the list. Use a project that is only for this purpose if you can, so you can see its usage separately.
  5. Copy the key. It usually starts with AIza, and newer keys can start with AQ.. Treat it like a password.

If AI Studio shows a “default project” or asks you to import one, import or create a project first. A key always belongs to a project.

The button is greyed out

If Create API key cannot be pressed:

  • Make sure you have accepted the terms in AI Studio.
  • Make sure you are signed in with a personal Google account. Accounts of schools and companies (Google Workspace) can have the Gemini API switched off by an administrator, and you may need to ask them or use a personal account.
  • Accounts of people under 18 cannot use the Gemini API.
  • The Gemini API is not offered in every country. If it is unavailable where you are, AI Studio says so.
  • If no project is listed, create or import one first, then try again.
  • Reload the page, or sign out and in again.

Free tier or billing

You do not need a credit card or any billing to use the AI DJ. The free tier has daily and per-minute limits that are enough for normal listening. The most limited part is the speech: only a small number of spoken breaks per day are included. When it runs out, the DJ shows its lines as text. See Quotas and the text fallback in AI DJ. Google decides the exact limits and may change them; AI Studio shows the current ones for your project.

Free-tier requests differ from paid ones in how Google handles your data. Outside the EU, UK and Switzerland, Google may use free-tier requests to improve its products and human reviewers may read them. Paid usage (billing enabled on the key’s project) is not used that way. The AI DJ sends song titles, artists, the DJ’s lines and your Details for the DJ, so decide whether you are comfortable with this. What is sent is listed on the AI DJ page.

If you enable billing to get higher limits:

  1. In the Google Cloud console open Billing, then Budgets and alerts, and create a budget for the project with an amount you are comfortable with, for example 5 euros.
  2. Add e-mail alerts at a few percentages of the budget.

A budget alert warns you, but it does not stop the spending by itself. The AI DJ uses small text and speech requests, so normal use costs little, but a key that someone else gets hold of can cost money.

Put the key into Listen

  1. Open Settings → Playback → AI DJ.
  2. Click into Gemini API key and paste the key.
  3. Press Save (or Enter). Listen stores the key in your system keyring and plays a short voice sample to test it.
  4. If the status line says that the persona works, switch Enabled on.

The key is never shown again; the field then shows dots. It is not written to the settings file.

Replace, rotate or remove the key

  • Replace or rotate. Create a new key in AI Studio, paste it into Gemini API key and press Save. Then delete the old key in AI Studio. Saving a new key also clears a “quota used up” state, which is useful if the new key is on a different project.
  • Remove. Clear the field and press Save with the field empty. Listen deletes the key from the keyring and switches the AI DJ off.
  • Revoke at Google. Delete the key in AI Studio. Listen then shows a “key was rejected” warning until you save a working key.
  • Restrict. In the Google Cloud console you can limit a key to the Generative Language API, which is the one Listen uses.

If your key leaks, for example because you posted a screenshot, delete it at once in AI Studio and create a new one.

Troubleshooting

  • “The Gemini API key was rejected”. The key was typed or pasted incompletely, has been deleted, or is restricted to something else. Copy it again and save.
  • A quota message. The free limits are used up. See AI DJ.
  • No keyring on your system. The key cannot be stored permanently. On Linux you need a running secret service such as GNOME Keyring or KWallet. See Troubleshooting.
  • Testing without the keyring. The environment variable LISTEN_GEMINI_API_KEY is used before the saved key.

Media keys and system controls

Listen tells your desktop what is playing and accepts commands back, so media keys, lock-screen style widgets and panel applets work without Listen having focus. On Linux this uses MPRIS; on Windows it uses the System Media Transport Controls (the media flyout).

Linux: MPRIS

Listen registers itself on the D-Bus session bus as an MPRIS media player named Listen. Anything that speaks MPRIS can show and control it: the KDE Plasma and GNOME media widgets, panel applets, playerctl, KDE Connect, and so on.

What the desktop sees:

  • Title, artists, album, album artist, track number, length and the cover.
  • Genre, disc number, BPM, comment, year, last played, play count and rating when the song has them.
  • The current lyrics (synchronised lyrics as LRC text) in the xesam:asText field.
  • Playback state, position, volume, shuffle and repeat (none, track, playlist).

What the desktop can do: play, pause, play/pause, stop, next, previous, seek (relative and absolute), set the volume, switch shuffle and repeat, and raise the Listen window. Listen cannot be quit over MPRIS, and it does not expose a track list.

The player appears as soon as Listen starts. If the session bus is not available, Listen logs a warning and carries on without it.

Windows: media flyout

On Windows, Listen publishes to the System Media Transport Controls. That gives you:

  • The media flyout (volume popup) and the lock screen with title, artist, album and cover.
  • Hardware media keys and keyboard media keys, and the media buttons on headsets and Bluetooth devices.
  • Play, pause, next, previous, stop, seeking and the position slider. The fast-forward and rewind buttons jump 10 seconds; the position slider sets an exact position.

Listen keeps a hidden helper window for this, so the controls keep working while the main window is hidden in the tray.

Media keys

PlatformHow the keys reach Listen
WindowsThrough the media flyout (SMTC). Nothing to set up.
Linux with KDE Plasma, GNOME, Cinnamon or BudgieThe desktop sends the keys to the running MPRIS player. Nothing to set up.
Other Linux desktops (for example sway or Hyprland)Listen asks the desktop portal to grab the keys itself. See below.

Global media keys through the portal (Linux)

Settings → Hotkeys → System-wide → Global media hotkeys (on by default) lets Listen register these keys with the desktop’s GlobalShortcuts portal:

ShortcutPreferred keyAction
Media key: play / pauseXF86AudioPlayPlay / pause
Media key: next trackXF86AudioNextNext track
Media key: previous trackXF86AudioPrevPrevious track
Media key: stopXF86AudioStopStop

Listen only registers these on desktops that do not already route the keys over MPRIS. On KDE Plasma, GNOME, Cinnamon and Budgie the setting has no effect, because binding the keys twice would make every press fire two times. Turn the setting off if you want only MPRIS to control Listen.

The portal treats the keys above as suggestions. The desktop has the final say, and may ask you to confirm or may bind a different key. The Hotkeys tab shows what the desktop actually assigned under “Active in the desktop”. To change a key the desktop already bound, open the desktop’s own settings (for example System Settings → Shortcuts → Listen).

If your desktop has no GlobalShortcuts portal, the Hotkeys tab shows “The desktop refused system-wide shortcuts” with the reason. MPRIS keeps working.

See Hotkeys for the other system-wide shortcuts.

Troubleshooting

  • Media keys do nothing on Linux: check that another player is not grabbing them, and that your desktop supports MPRIS or the GlobalShortcuts portal.
  • On Windows the flyout shows an old song: it updates when the song changes; pausing and resuming refreshes it.
  • A key fires twice on a non-listed desktop: turn Global media hotkeys off and let MPRIS handle it.

Hotkeys

Listen has a hotkey editor with one row per action. Hotkeys work inside the Listen window; on Linux you can also make most playback actions work system-wide. Open Settings → Hotkeys.

Recording a hotkey

  1. Open Settings → Hotkeys.
  2. Click the field in the row of the action. It shows “Press keys…”.
  3. Press the key combination you want. The field takes the first valid combination.
  4. To cancel, press Esc. To remove a binding, click the cross at the end of the row.

Notes:

  • Mod means Ctrl. Combinations can use Ctrl, Alt, Shift and the Super/Windows key plus one key.
  • A field with a red border means the same combination is used by another action.
  • Every action starts unbound except the defaults in the table below.

Actions

“Global” means the action can be made system-wide on Linux (see below). Actions marked “No” only work while the Listen window has focus.

ActionWhat it doesDefaultGlobal
Browser backGo back one pagenoneNo
Browser forwardGo forward one pagenoneNo
Favorite current songLike the playing songnoneYes
Unfavorite current songRemove the like from the playing songnoneYes
Toggle current song favoriteLike or unlike the playing songnoneYes
Favorite previous songLike the queue entry before the playing onenoneYes
Unfavorite previous songUnlike that entrynoneYes
Toggle previous song favoriteToggle the like of that entrynoneYes
Global searchOpen the command palette and searchCtrl+KNo
List: navigate to pageOpen the page of the selected rowCtrl+GNo
List: play (default)Play the selected rows the default wayEnterNo
List: play lastAdd the selected rows to the end of the queuenoneNo
List: play nextPlay the selected rows after the current songnoneNo
List: play nowReplace the queue with the selected rows and playnoneNo
List: show playing songScroll the list to the playing songCtrl+LNo
Local searchFocus the search field in the sidebarCtrl+FNo
Navigate to homeGo to the Home pagenoneNo
Next trackSkip to the next songnoneYes
Next albumSkip to the first song of the next albumnoneYes
PausePause (does nothing when already paused)noneYes
PlayResume (does nothing when already playing)noneYes
Play / pauseToggle playbackSpaceYes
Previous trackGo to the previous songnoneYes
Previous albumGo to the previous albumnoneYes
Rate 0 starsClear the rating of the playing songnoneYes
Rate 1 starRate the playing song 1 starnoneYes
Rate 2 stars2 starsnoneYes
Rate 3 stars3 starsnoneYes
Rate 4 stars4 starsnoneYes
Rate 5 stars5 starsnoneYes
Skip backwardJump back by the skip amountnoneYes
Skip forwardJump forward by the skip amountnoneYes
StopStop playbacknoneYes
Toggle full-screen playerOpen or close the full-screen playernoneNo
Toggle heart-rate tempoSwitch heart-rate tempo on or offnoneYes
Toggle queueShow or hide the queuenoneNo
Toggle repeatCycle repeat: off, all, onenoneYes
Toggle shuffleSwitch shuffle on or offnoneYes
Volume downLower the volume by one stepnoneYes
Volume muteMute or unmutenoneYes
Volume upRaise the volume by one stepnoneYes
Zoom inMake the interface largernoneYes
Zoom outMake the interface smallernoneYes

Details:

  • Skip backward and forward use the amounts from the player bar settings (5 and 10 seconds by default). The volume step is the volume wheel step from the same settings.
  • Rating hotkeys do nothing for sources without ratings, such as YouTube Music.
  • Hotkeys that act on a list (the “List:” actions) use the rows you selected in the list that is on screen. See Lists, selection and menus.
  • Window hotkeys are ignored while the command palette is open.

System-wide shortcuts (Linux)

On Linux the editor has an extra checkbox at the end of each row for actions marked “Global”. Tick it (after you have bound a key) and Listen registers the shortcut with the desktop’s GlobalShortcuts portal, so it works from any window, including on Wayland. This is supported by KDE Plasma and GNOME, among others.

  • The key you record is only a suggestion. The desktop owns the final choice and may show a confirmation dialog or pick another key. The System-wide section shows “Active in the desktop: …” with what was really bound.
  • A global action no longer fires from inside the Listen window, only from the portal, so it never runs twice.
  • To change a key the desktop has already bound, use the desktop’s shortcut settings (for example System Settings → Shortcuts → Listen).
  • If the portal is missing or refuses, a red message at the top says so, and the actions fall back to working inside the window only.
  • Global media hotkeys is the separate switch for the hardware media keys; see Media keys and system controls.
  • Clearing a hotkey also removes its global flag.

Windows

Hotkeys work while the Listen window has focus. There are no system-wide shortcuts for the editor’s actions on Windows; use the hardware media keys, which work through the media flyout (see Media keys and system controls), or the tray menu.

Tray, window and notifications

This page covers how Listen behaves as a desktop window: the tray icon, closing and minimising, starting hidden, running only once, remembering its size, the title bar, keeping the computer awake, song-change notifications and scrobbling. Most of it is under Settings → Window; scrobbling is under Settings → General → Scrobble.

Tray icon

Tray icon (on by default) shows Listen in the system tray. On Linux this uses the StatusNotifierItem standard (KDE Plasma supports it; GNOME needs the AppIndicator extension). On Windows it is a normal notification-area icon.

Left-click the icon to show the window. Right-click for the menu:

  • Play / Pause
  • Next Track
  • Previous Track
  • Stop
  • Open main window
  • Quit

The tooltip shows the playing song. Quit from the tray ends Listen completely.

Turning Tray icon off hides the three options below.

Close, minimise and start hidden

These options appear when Tray icon is on. All are off by default.

SettingEffect
Minimize to trayMinimising hides the window in the tray. Click the tray icon to show it again; with this option on, a click on the icon while the window is open hides it.
Close to trayThe close button hides the window instead of quitting. Music keeps playing; use the tray menu’s Quit to exit.
Start minimizedListen starts with only the tray icon and no window. If no tray is available, the window opens anyway so you are never locked out.

Note: Close to tray and Minimize to tray hide the window on Linux. On Windows the tray icon and its menu work, but at the moment the close and minimise buttons behave normally there.

On Wayland, a hidden window is really closed and a fresh one is opened when you bring it back, because Wayland applications cannot hide or restore their own window. You will not notice this apart from a short flicker.

One instance

Only one Listen runs per user. Starting it a second time (from the launcher, a file manager or the command line) does not open a second player: the running one comes to the front and the new process exits. The --route option of the command line is handed over the same way to open a page in the running instance.

Window size and position

Listen remembers the size, position (where the system allows), maximised and full-screen state of the main window and restores them at the next start. It is saved shortly after you stop resizing or moving the window, and again when you close it.

If a saved position is off-screen (for example the monitor was unplugged), the window is moved back onto a display, and it is shrunk if it is bigger than the display. On Wayland, Listen cannot read or set the position, so only the size and the maximised/full-screen flags are restored. The default size is 1600 by 950.

Title bar

Window bar style chooses how the top of the window looks:

ChoiceMeaning
Windows (default)Listen draws its own bar with Windows-style buttons.
macOSListen draws its own bar with macOS-style buttons on the left.
NativeThe desktop draws the normal window frame.

The change applies immediately. Track info in window title (on by default) puts the playing song in the title, as “(3 / 40) Song - Artist - Listen”; a paused song starts with “Paused”. With it off, the title is just “Listen”. In private mode the title ends with “(Private mode)”.

Keep the computer awake

Two switches stop the computer from sleeping while music plays:

  • Prevent display sleep while playing: keeps the screen on, and the system awake.
  • Prevent system sleep while playing: stops the system from suspending; the screen may still turn off. This switch is on and locked while the display switch is on, because that already covers it.

Listen holds the lock only while a song is playing and releases it when you pause or stop. On Linux it uses the desktop’s Inhibit portal; if the portal is missing, a warning appears in the log and nothing is held. Both are off by default.

Song change notifications

Settings → General → Scrobble → Song change notifications (off by default) shows a desktop notification when the song changes, with the title, artists, album and the cover as the icon. The notification is silent. Skipping through several songs quickly shows only the one you land on, after it has played for a second. Notifications use the freedesktop notification service, so they are available on Linux.

Scrobbling

Scrobbling reports your plays to the music server and, once connected, straight to Last.fm (see Last.fm). It is under Settings → General → Scrobble.

SettingMeaningDefault
ScrobbleReport plays to the server.On
Scrobble minimum modeWhen a play counts: Percentage or seconds (whichever comes first), Percentage, or Seconds.Percentage or seconds
Minimum scrobble percentageShare of the song that must be played, 25 to 90 %. Hidden in Seconds mode.75 %
Minimum scrobble secondsTime that must be played, 0 to 1200 s in steps of 5. Hidden in Percentage mode.240 s

Skipping ahead inside a song does not count as listening, only the time actually played counts. When a song starts, Listen also tells the server “now playing”; the scrobble itself is sent once the threshold is reached.

What happens on each source:

  • Navidrome and other OpenSubsonic servers: the server’s scrobble call (now playing, then submission). Navidrome forwards it to Last.fm or ListenBrainz if you linked an account in Navidrome.
  • Jellyfin: a “now playing” session report, then the item is marked as played.
  • YouTube Music: the play is added to your YouTube Music history (not for guest sessions).
  • Local folders and radio: nothing is reported.

Last.fm

Listen can scrobble to Last.fm itself, for every source: YouTube Music, Navidrome, Jellyfin and local folders alike. It uses the same rule as above for when a play counts, and shows the song as “now playing” on your profile while it plays.

  1. You need a Last.fm API account (free, made with your normal Last.fm login at last.fm/api/account/create). Under Settings → General → Scrobble → Last.fm, enter its API key and Shared secret.
  2. Press Connect to Last.fm. Your browser opens Last.fm; allow access there. Listen notices it within a few seconds and shows Connected as your user name.
  3. Disconnect forgets the sign-in. Scrobble to Last.fm pauses sending without signing out.

The shared secret and the sign-in are kept with your server passwords (keyring), not in the settings file.

One name per song. The same song is often spelled differently by different sources: “Ditto (Official Audio)” on YouTube Music, “Ditto” in your tags; “뉴진스 (NewJeans)” or “NewJeans”; “OMG - Single” or “OMG”; an artist’s Korean and international name. Last.fm would count each spelling as a track of its own. Before a play is sent, Listen asks Last.fm which spelling of the artist, the title and the album most people use, and sends that one: upload labels such as “(Official Audio)” or “[MV]” go, “ - Single“ and “ - EP“ go, and an artist’s other name is used when Last.fm itself ties the two together (same MusicBrainz id, or the artist’s Last.fm biography names the other). The album is the one Last.fm files the track under, so the same song gets the same album from every source. The answers are kept for 30 days in lastfm/lastfm-names.json in Listen’s data folder.

Offline. Plays go into lastfm/lastfm-queue.json first and are sent in batches of up to 50. Plays made offline or while Last.fm is down are sent later (Last.fm accepts plays up to 14 days old). A short bridge stretch of the DJ is never scrobbled, and nothing is sent in private mode.

If you scrobble to Last.fm from Listen, unlink Last.fm in Navidrome (user menu → Personal → Scrobble to Last.fm off); otherwise Navidrome songs arrive twice.

Nothing is scrobbled in private mode. Turn it on under Settings → Window → Private mode (or in the application menu). In private mode nothing is scrobbled, shown on Discord or saved to the local history, and the window title says so. It switches off again when Listen restarts.

Discord status

Listen can show what you are listening to as a Discord Rich Presence status. It is off by default and needs the Discord desktop app to be running on the same computer. The settings are under Settings → Window.

Turning it on

  1. Start the Discord desktop app.
  2. Open Settings → Window and switch on Discord Rich Presence.
  3. Play a song. Your Discord profile shows it within a few seconds.

If Discord is not running, Listen cannot connect and tries again with the next update (Listen re-sends the status every 15 seconds). Nothing is shown in private mode.

Options

SettingWhat it doesDefault
Discord Rich PresenceMaster switch.Off
Discord application IDThe Discord application whose name and logo the status uses. Press Enter to apply.Listen’s own application
Show presence when pausedKeep the status while paused, with a paused icon and no timer. Off clears the status on pause.On
Show playing iconSmall “playing” icon next to the cover.On
Show status as listening“Listening to …” instead of “Playing …”.Off
Discord display typeWhat the short status line under your name shows: Listen (the application name), Song name or Artist name.Listen
Discord link typeMake the song, artist and cover clickable: None, Last.fm, MusicBrainz, or MusicBrainz (Last.fm fallback).None
Show server cover imageSend the cover from your music server to Discord.Off
Last.fm API keyLook up the album cover on Last.fm when there is no other cover. Press Enter to save.empty (off)

The status shows the song as the first line, the artists as the second, the album as the cover’s tooltip and, while playing, a progress timer. Lines are cut at 127 characters.

  • Last.fm links the artist to its Last.fm page and the song and cover to the album and track pages.
  • MusicBrainz links use the MusicBrainz ids your server stores for the song (track or recording id, and release id for the cover). Servers that do not provide ids give no link.
  • MusicBrainz (Last.fm fallback) uses MusicBrainz where ids exist and Last.fm otherwise.

Covers

Discord can only load images from public web addresses, so Listen picks a cover in this order:

  1. A YouTube Music song uses its public https thumbnail.
  2. With Show server cover image on, a song from a server that is reachable from the internet over https (a public host name, not a local name or private address) uses the server’s cover. The link includes your server’s access token, so Discord and the people who see your status can in principle read it. Only switch this on for a server you are comfortable exposing that way.
  3. With a Last.fm API key, the album cover is looked up on Last.fm (a free key from Last.fm’s API pages). Results are cached for the session.
  4. Otherwise Listen’s logo is shown.

Covers from local folders are never sent.

Listen’s own Discord application

By default the status uses an application registered for Listen, so Discord shows the name “Listen” and Listen’s logo. If you prefer your own name and artwork, create an application in the Discord Developer Portal, upload an asset named icon (plus playing and paused if you want the small icons), and paste its application ID into Discord application ID.

Private mode

With Private mode on (Settings → Window → Private mode or the application menu), Listen clears the status and does not show anything on Discord until you turn it off again or restart Listen. Private mode also stops scrobbling and history; see Tray, window and notifications.

Remote control

Listen can serve a small web page that works as a remote control for your phone or another computer on your network. It is off by default. The settings are under Settings → Window → Remote control.

Turning it on

  1. Open Settings → Window → Remote control.
  2. Switch on Enable remote control server. The row then shows “Running: open http://…:4333 on the phone”. If it cannot start (for example the port is taken), it shows “Not running” and the reason.
  3. On the phone, open that address in a browser, replacing localhost with this computer’s address on your network, for example http://192.168.1.20:4333.
  4. Optionally use the browser’s “Add to Home Screen” to install the page like an app.

Settings

SettingMeaningDefault
Enable remote control serverStarts and stops the server.Off
Remote server portTCP port, 1 to 65535. Press Enter to apply.4333
Remote server address0.0.0.0 lets other devices in your network connect; 127.0.0.1 only this computer. Press Enter to apply.0.0.0.0
Remote server usernameUser name for sign-in.empty
Remote server passwordPassword for sign-in. Stored in the system keyring, not in the settings file. Press Enter to save; Enter on an empty field clears it.empty

Leave both username and password empty for no sign-in. If you set either, the browser asks for a login (HTTP basic authentication) before it shows the page.

What the page can do

The page has six tabs:

TabContent
HomeCover, title and artist, seek bar, shuffle, previous, play/pause, next, repeat, volume slider, favourite heart and star rating. While internet radio plays it shows the station name.
QueueThe queue with the playing entry highlighted. Tap an entry to jump to it, the cross removes it, and Clear queue empties it.
AlbumsSearchable list of albums; tap to play.
PlaylistsYour playlists; tap to play.
RadioInternet radio stations; tap to play.
TracksSearchable list of songs; tap to play.

The star rating only appears for songs from a server that supports ratings. The page updates live over a WebSocket and reconnects on its own if the connection drops. Its message format is compatible with the Feishin remote.

Security

  • The page and the connection use plain HTTP and WebSocket, without encryption. A basic-auth password is therefore visible to anyone who can watch your network traffic. Use the remote only on a network you trust, or keep the address at 127.0.0.1 and reach it through your own secure tunnel.
  • With an empty username and password and an address other than 127.0.0.1, Listen shows a red warning: “Anyone in your network can control Listen. Set a username and password.”
  • The page only receives what it needs: the song’s details and the cover, which Listen serves itself at /cover. Your music server’s address, login and tokens never leave Listen.
  • Do not forward the port to the internet.
  • Some systems ask you to allow Listen through the firewall the first time the server listens on a network address.

To use Listen from an AI assistant rather than a phone, see MCP server.

Continue on another device

With your own listen-server set up (Settings, Advanced, Listening history: the listen-server address and token), Listen on your computers and on the Android app knows what the others play.

  • While another device plays, a strip above the player bar shows it: Playing on Phone: song · artist. Play here moves the music to this computer.
  • Play on a device where nothing plays continues what another device plays, or what it played until a few minutes ago (10 minutes), at the same spot, with its queue.
  • Connecting headphones (or any new audio output) to a device where nothing plays does the same when another device plays or stopped in the last 3 minutes. Take your Bluetooth headphones from the computer to the phone and the song goes along.

The device that played pauses and says where the music went. Songs that can’t play on the new device (a local folder only that device has) are left out of the queue; if the current song is one of them, nothing moves and Play plays this device’s own queue.

Turn it off with Continue on other devices in Settings, Advanced, Listening history. The wire format is in docs/handoff.md in the source repository.

MCP server

Listen has a built-in Model Context Protocol (MCP) server. It lets an AI assistant that supports MCP, such as Claude Code or Claude Desktop, play music, manage the queue and playlists, change the AI DJ and adjust settings for you. The server runs inside Listen on your own computer; nothing is hosted elsewhere. It is off by default.

Turning it on

  1. Open Settings → Window → MCP server.
  2. Switch on Enable MCP server. The row then shows “Running at http://127.0.0.1:4334/mcp”.
  3. Listen creates an access token the first time it is needed and keeps it in the system keyring.
SettingMeaningDefault
Enable MCP serverStarts and stops the server.Off
MCP server portTCP port, 1024 to 65535. Press Enter to apply.4334
Allow other computersOff: only programs on this computer can connect (127.0.0.1). On: the server listens on all network addresses.Off
Access tokenCopy token copies it; New token makes a new one and disconnects every client.created on first use
Connect Claude CodeCopy command copies a ready-made claude mcp add command.

If the server cannot start, for example because the port is in use, the row shows “Not running” with the reason. Pick another port and press Enter.

Connecting a client

Every request must carry the header Authorization: Bearer <token>. The endpoint is http://127.0.0.1:4334/mcp (use your port; for another computer use this computer’s address instead of 127.0.0.1).

Claude Code

Press Copy command and run it in a terminal, or type it yourself:

claude mcp add --transport http listen http://127.0.0.1:4334/mcp --header "Authorization: Bearer <token>"

Start a new Claude Code session afterwards. The tools appear as listen.

Claude Desktop and other clients

Clients that support remote (HTTP) MCP servers take the URL and the header. Press Copy token to get the token.

Clients that only speak stdio can use a bridge such as mcp-remote. For Claude Desktop, add this to its claude_desktop_config.json, with your own token:

{
  "mcpServers": {
    "listen": {
      "command": "npx",
      "args": [
        "mcp-remote",
        "http://127.0.0.1:4334/mcp",
        "--header",
        "Authorization: Bearer <token>"
      ]
    }
  }
}

This needs Node.js (for npx). Restart the client afterwards.

What the server speaks

Streamable HTTP with JSON answers. Only POST /mcp is offered: there are no sessions and no server-sent event stream, so a GET gets “405 Method Not Allowed”. It understands the protocol revisions 2025-06-18, 2025-03-26 and 2024-11-05. Up to 16 clients can be connected at once.

What an assistant can do

AreaWhat it can do
PlaybackRead what plays; play, pause, skip, seek; volume, play mode, repeat, speed; start a sleep timer.
QueueRead the queue; play or add songs, albums, artists and playlists; jump, remove, move, shuffle or clear.
LibraryList servers and switch the active one; search; open albums, artists and playlists; start a radio; read the lyrics of the playing song.
PlaylistsCreate, fill, trim, rename and delete playlists on your servers.
FavouritesLike or unlike, and rate, songs, albums and artists.
AI DJRead and change the persona, voice model, language, location, notes and set size; store or remove the Gemini key.
SettingsRead all settings and change any of them with a partial JSON object.
AnalysisCheck the progress of the song analysis for DJ transitions.

The complete list with every argument is in MCP tools.

Example prompts

  • “What is playing right now, and what is next in the queue?”
  • “Search for albums by Radiohead and play the newest one.”
  • “Make a playlist called Sunday Morning with ten calm songs from my library.”
  • “Add the songs from this album to my playlist Road Trip.”
  • “Lower the volume to 30 percent and stop the music in 45 minutes.”
  • “Turn on the AI DJ with the evening persona and set the language to German.”
  • “Switch the gapless setting to yes.”
  • “Remove everything after the current song from the queue.”

The assistant first searches, which returns references to songs, albums and so on, and then passes those references to the next tool. You do not need to know them.

Security

  • Only programs on this computer can connect, unless you switch on Allow other computers. Even then every request needs the token. Listen shows a red warning while the server is open to the network.
  • Web pages in your browser cannot talk to the server: requests that come from a web page on another site (an Origin that is not localhost) are refused.
  • Whatever has the token can control Listen fully: change settings, edit or delete playlists on your servers, and use your Gemini quota through the AI DJ. Treat the token like a password and do not paste it into shared places.
  • No tool ever returns a password, cookie, API key or the token. get_settings leaves them out, and get_ai_dj only says whether a Gemini key is stored.
  • The connection is plain HTTP. On your own computer that is fine; over a network, anyone who can see the traffic can read the token. Prefer keeping Allow other computers off and using an SSH tunnel or similar if you need access from elsewhere.
  • Destructive tools (clear_queue, delete_playlist) run without asking Listen’s confirmation dialog. Most MCP clients ask you before they run a tool; keep that on for these.
  • New token immediately disconnects every client. Update the token in each client afterwards.

Themes and colours

This page explains how to change the look of Listen: the theme, light and dark mode, the accent colour, fonts, zoom and a few related options. All of them are on the Settings > General tab, in the Appearance and Application sections. To make your own theme, see Custom themes.

Choosing a theme

Listen ships with 32 themes plus six desktop presets, and it can load your own. Which picker you see depends on Follow system theme:

  • Follow system theme on (the default): you choose a Dark theme and a Light theme. Listen uses the one that matches the desktop’s light or dark setting and switches when the desktop does. The defaults are Tokyo Night (dark) and Default Light (light).
  • Follow system theme off: you choose one Theme that is always used. The default is Default Dark.

Every picker lists the same themes: the built-in ones, the desktop presets, and your own themes with “(custom)” after their name.

Built-in themes

DarkLight
Ayu Dark, Catppuccin Mocha, Default Dark, Dracula, Everforest Dark, Github Dark, Glassy Dark, Gruvbox Dark, High Contrast Dark, Material Dark, Monokai, Night Owl, Nord, One Dark, Rose Pine, Rose Pine Moon, Shades Of Purple, Solarized Dark, Tokyo Night, Vscode Dark Plus, ZenburnAyu Light, Catppuccin Latte, Default Light, Everforest Light, Github Light, Gruvbox Light, High Contrast Light, Material Light, Rose Pine Dawn, Solarized Light, Vscode Light Plus

The set is the same as in Feishin, which Listen’s interface is modelled on.

Following the desktop theme

On Linux, Follow desktop theme (on by default) makes Listen use the colours of your desktop instead of a built-in theme. It reads the KDE colour scheme (kdeglobals, including the accent colour) and follows changes live, usually within a second. When it is on, it takes precedence over the theme choices below it. The row’s description tells you what Listen found. If no desktop colours can be found, Listen uses the theme you picked.

The six presets named “(desktop)” in the pickers (Tokyo Night, Catppuccin Mocha, Gruvbox Dark, Nord, Rosé Pine, Dracula) are hand-tuned palettes. Listen selects one of them automatically when a compatible theme-switcher script on your desktop announces it.

This row does not exist on Windows. There, use Follow system theme.

Accent colour and shades

The accent colour is used for the primary buttons, active items and highlights.

  • Use the theme’s accent colour: when on, each theme keeps its own accent. When off (the default), your accent replaces the theme’s.
  • Accent colour: pick one of five swatches, or type any rgb(r, g, b) or #rrggbb value in the field. The default is rgb(53, 116, 252). The field and swatches are disabled while the previous option is on.
  • Use the theme’s primary shade: when on (the default), buttons and links use the shade the theme prescribes.
  • Primary shade: when the previous option is off, a slider from 0 (lightest) to 9 (darkest) picks which shade of the accent colour buttons and links use. The default is 6.

Fonts

SettingWhat it does
Font typeBuilt-in (Inter or Poppins, bundled with Listen), System (any font installed on the computer) or Custom (a font file).
FontThe family used for all text. For System fonts, the list fills in after a moment.
Font fileCustom only. The path to a .ttf, .otf or .ttc file; press Use to load it. An error is shown under the field if the file cannot be read.

The default is the built-in Inter.

Zoom

Zoom scales the whole interface from 50 % to 300 % in steps of 5 %. The default is 100 %. The change applies when you let go of the slider. The - and + buttons step by 5, Reset returns to 100 %. The zoom hotkeys (see Hotkeys) change the same value.

Backgrounds, covers and scrolling

SettingWhat it doesDefault
Album background imageShows the blurred cover behind the header of album pages. The slider sets the blur from 0 to 6.On, 3.0
Artist background imageThe same for artist pages.On, 3.0
Blur explicit imagesBlurs the covers of songs tagged explicit.Off
Native cover aspect ratioShows covers whole instead of cropped to a square.Off
Image placeholderWhat a cover shows while it loads: ThumbHash (a blurred preview, available from the second time a cover loads), Colour (a tint taken from the cover) or Off.Colour
Touchpad scroll speedHow far a swipe scrolls, from 25 % to 200 %. At 100 %, scrolling matches Chromium-based browsers for the same swipe.100 %

Where the values are stored

All of these are stored under settings.appearance in config.toml. See the settings reference for every key.

Custom themes

You can add your own colour themes as small text files, and change colours, corner radii, spacing and font sizes of any theme with an override file. Listen reloads them while it runs.

The themes folder

Custom themes live in the themes folder inside Listen’s config folder (~/.config/listen/themes on Linux). To open it, go to Settings > General > Appearance and press Open folder on the Custom themes folder row. The row also shows how many custom themes were found and whether an override file is active.

Files can be JSON or TOML. Listen notices changes within about a second, so there is no need to restart: save the file and the theme picker and the interface update. Your themes appear in the theme pickers as “Name (custom)”.

A theme file

Create <name>.json or <name>.toml in the folder. The file name (without the extension) is the theme’s id.

{
  "name": "Sunset",
  "extends": "tokyoNight",
  "mode": "dark",
  "colors": {
    "background": "#1d1214",
    "surface": "rgb(42, 26, 29)",
    "primary": "#ff8844"
  }
}

The same theme in TOML:

name = "Sunset"
extends = "tokyoNight"
mode = "dark"

[colors]
background = "#1d1214"
surface = "rgb(42, 26, 29)"
primary = "#ff8844"
KeyMeaning
nameThe name shown in the pickers. Defaults to the file name.
extendsThe theme to start from: a built-in theme id (for example tokyoNight or defaultLight) or another file in the folder. Your colours win over the parent’s. Chains can be up to 10 deep; a loop is an error. Without extends, the theme starts from defaultDark, or from defaultLight if mode is light.
modedark or light. Defaults to the parent’s mode.
colorsThe colours you want to change.

Colours

Keys are written in kebab-case:

background, background-alternate, foreground, foreground-muted, primary, state-error, state-info, state-success, state-warning, surface, surface-foreground

Values can be #rgb, #rrggbb, #rrggbbaa (the alpha part is ignored) or rgb(r, g, b). Colour names such as blue are not accepted.

The built-in theme ids are the names in the themes list written in camel case: defaultDark, catppuccinMocha, rosePineDawn, vscodeDarkPlus, solarizedLight and so on.

Note: Your accent colour setting still replaces primary unless Use the theme’s accent colour is on.

The override file

overrides.json or overrides.toml in the same folder is applied on top of whichever theme is active, including the desktop theme. Use it to tweak things without making a whole theme. Every key is optional.

[colors]            # the theme colours above, plus:
border = "#ffffff1a"
divider = "#ffffff0d"
nav-hover = "#2a2a3a"
icon-hover = "#26263a"
player-bar = "#101018"
primary-filled = "#3574fc"   # buttons, active navigation
primary-shade = "#2f63d6"    # links, selection outlines

[radius]            # pixels, 0 to 32: sm, md
sm = 3
md = 8

[spacing]           # pixels, 0 to 64: xs sm md lg xl
lg = 20

[font_size]         # pixels, 6 to 48: xs sm md lg xl
md = 15

Colours, radii, and the look of buttons, inputs and containers follow the override immediately. Spacing and font sizes apply to every screen.

When something is wrong

Problems are listed in red or grey under the Custom themes folder row in Settings:

  • A file that is not valid JSON or TOML, is not an object, or has an unknown extends is listed as an error and that theme is skipped.
  • A loop in extends, or a chain longer than 10, is an error.
  • Two files with the same name (for example sunset.json and sunset.toml) are an error.
  • An invalid colour value is dropped with a note, and the rest of the theme still loads. The same goes for unknown colour keys, an unknown mode, and out-of-range or non-numeric override values.

Fix the file and save it; the list updates on its own.

Languages

Listen’s interface is available in 17 languages. This page explains how to switch, how the AI DJ’s language fits in, and how to help.

Changing the interface language

Go to Settings > General > Application > Language and pick a language. The change applies after you restart Listen.

The choices are System default and these languages, each shown in its own language:

Englishالعربية (Arabic)বাংলা (Bengali)
Deutsch (German)Español (Spanish)Français (French)
हिन्दी (Hindi)Italiano (Italian)한국어 (Korean)
Nederlands (Dutch)Polski (Polish)Português (Portuguese)
Română (Romanian)Русский (Russian)Українська (Ukrainian)
اردو (Urdu)简体中文 (Simplified Chinese)

System default (the default) follows your computer’s language, read from the LC_ALL, LC_MESSAGES or LANG environment variable on Linux. If your language is not in the list, Listen uses English. Any Chinese locale maps to Simplified Chinese.

Text that has not been translated yet is shown in English.

The AI DJ’s language

The AI DJ has its own language setting, so the hosts can speak a different language from the one the interface uses. Find it under Settings > Playback > AI DJ > Language. The default, Same as the app, follows the interface language. Song titles stay in their own language.

The language of lyrics translation (Settings > Playback > Lyrics > Translation language) is a separate setting too.

Helping to translate

Translations are plain JSON files in the source repository, and corrections or new languages are welcome. See Translations for the file layout and how to send a change.

Where the setting is stored

settings.appearance.language holds the language code (for example de or zh-Hans); an empty value means System default. The AI DJ’s code is settings.ai_dj.language.

CD ripping

Listen can rip audio CDs on Linux. Put a disc in the drive and Listen makes a secure copy, tags it from MusicBrainz, adds cover art and files the album into your music folder, much like the auto-rip of MusicBee. This page covers the setup, every option under Settings → Advanced → CD ripping, and how to check a rip.

Note: CD ripping is available on Linux only. It uses the separately installed program whipper. On Windows the CD ripping section does not do anything.

What you get

  • A secure rip with whipper (Test & Copy, checked against AccurateRip).
  • Always FLAC at compression level 8.
  • Tags and track names from MusicBrainz, cover art embedded in every file and saved as cover.jpg.
  • ReplayGain tags for each track and for the album.
  • Files named Album Artist/Album/NN Title.flac. Multi-disc releases use D-NN Title.flac.
  • A notification when the album is done, and the disc is ejected.

Setup

  1. Install the tools. On Fedora the Listen RPM already pulls them in. Elsewhere install whipper, flac and cdrdao with your package manager, for example:

    sudo dnf install whipper flac cdrdao
    
  2. Run the check without a disc, or better with one in the drive:

    listen --check-cd
    

    It lists the tools, the drive and its read offset, the disc’s table of contents and MusicBrainz match, the music folder and your Navidrome server, and ends with “ready to rip” or the number of problems it found. See Checking a rip.

  3. Open Settings → Advanced → CD ripping and set the Music folder.

If you plug in a USB drive later, Listen picks it up. The section shows the drive, its device (for example /dev/sr0) and the read offset it will use. Without a drive it says “No CD drive connected”.

The settings

SettingDefaultWhat it does
Auto-rip inserted CDsonStarts ripping as soon as an audio CD goes into the drive, also while Listen sits in the tray. Turn it off to rip only with Rip CD.
Music folderyour system Music folder, such as ~/MusicWhere albums are filed. Type a path and press Save, or use Choose… to pick a folder. It can be a network share, for example the folder your Navidrome server scans (/mnt/nas/Music). Listen never deletes or overwrites anything in it.
Eject when doneonEjects the disc after the rip.
Notification soundonPlays a sound with the “Album ripped” notification. The sound needs pw-play (PipeWire); without it you get the notification only.
ReplayGain tagsonMeasures track and album loudness while tagging, so players can even out volume.
Scan Navidrome afterwardsonAsks the active Navidrome server to scan for the new album. This needs an admin login. Without one, the server’s own file watcher finds the album within a minute or two.
Version picker30 s (5 to 120 s, in steps of 5)How long Listen waits when several MusicBrainz releases match the disc (for example regional editions) before it takes the best match.
Drive read offsetautomaticThe read offset of your drive in samples. See below.
Rip nowThe Rip CD button rips the disc in the drive, also one you ripped before. It appears when a drive is connected.

Destination that is not available

If the music folder is a network share that is not mounted, the rip waits and tries again every 30 seconds. The panel says “Waiting for the music folder”. You can pick another folder with Choose folder… or press Retry. Listen first copies the finished album into a hidden .listen-incoming folder inside the destination and then renames it into place in one step, so a half-copied album never shows up in your library.

Read offset

Every CD drive reads audio shifted by a small number of samples. AccurateRip needs the right value to confirm that your copy matches other people’s. Listen takes the offset from, in this order:

  1. The number you saved in Drive read offset.
  2. whipper’s own configuration (~/.config/whipper/whipper.conf, written by whipper offset find).
  3. The AccurateRip drive list built into Listen, matched by the drive’s model name.

The line under the setting shows which one is used, for example read offset +48 (AccurateRip).

If the drive is not in the list, the line says the offset is unknown and a rip stops with a message asking you to set it. Either type the offset into the field and press Save, or press Verify offset. Verify offset runs whipper’s offset search, which takes a few minutes and needs a well-known, commercially pressed CD in the drive. When it succeeds the result is stored in whipper’s configuration. The offset is a whole number between -3000 and 3000, with or without a plus sign. Clear the field and press Save to go back to automatic.

What happens when you insert a disc

StepWhat Listen does
DetectNotices the disc through UDisks2. This also works while Listen is only in the tray.
RipRuns a whipper secure rip with the drive’s read offset.
IdentifyLooks up the MusicBrainz disc ID; if that fails, uses CD-Text; if that fails, names the album “Unknown Album (…)”.
Several matchesShows a picker with the matching releases. You can change the choice until tagging starts; after the timeout the best match is taken.
CoverCover Art Archive first (the release, then the release group), then iTunes. The image is scaled to 1200 px, embedded and saved as cover.jpg.
PublishCopies the album into .listen-incoming and renames it into place.
NavidromeAsks for a scan if the option is on and you are signed in as an admin.

The panel shows progress (“Ripping track 3 of 12”, “Tagging”, “Copying to the music folder…”) and ends with the folder and the AccurateRip result. While a rip runs you can press Cancel. Cancelling, or pulling the disc, leaves nothing in the music folder.

If some tracks could not be read perfectly, the panel asks “Publish the rest anyway?” with Publish anyway and Discard.

Rips to fix

If MusicBrainz does not know the disc, Listen still rips and files it as “Unknown Album (…)”, using CD-Text if the disc has it. Such discs are listed under Rips to fix (not on MusicBrainz) in the CD ripping section, newest first, with the album folder and a link: “Add the disc: …”. Open the link, add the release to MusicBrainz, then press Rip CD again to rip the disc with proper tags. The list shows the last 10.

Checking a rip

  1. Run listen --check-cd with a disc inserted. It shows the track list, the disc ID, the MusicBrainz matches (best first, marked with an arrow), the cover it found and the exact folder and file name the album would get. It does not rip anything.
  2. After a rip, open the album folder. You should see NN Title.flac files, cover.jpg and <Album>.log (whipper’s log). No .listen-incoming folder should remain. metaflac --list on a file shows the tags, MusicBrainz IDs, cover and ReplayGain values.
  3. Logs: Listen’s own listen.log and one rip-<date>-<disc id>.log per rip are in the logs folder, ~/.local/share/listen/logs/. See Backup, logs and diagnostics.

For problems with the tools, drive or share, see Troubleshooting.

Importing from Feishin

Listen’s interface is modelled on Feishin, and it can read a Feishin settings export so you do not have to set everything up again. This page explains where to find the option, what is taken over and what is not.

How to import

  1. Get a Feishin settings file: a JSON export of Feishin’s settings.
  2. In Listen open Settings → Advanced and scroll to Import from Feishin.
  3. Type or paste the path to the file in Feishin settings file, for example ~/Downloads/feishin-settings.json. A leading ~ is your home folder.
  4. Press Import (or Enter).

Tip: Instead of typing the path you can drag the file into the Listen window while Settings is open. It is imported right away.

Listen shows “Feishin settings imported.” and applies the values at once. If the file cannot be read or is not a Feishin file, an error message tells you why, and nothing changes.

The import works the same on Linux and Windows, because it only reads the file you point to. Listen does not look for Feishin’s own configuration folder by itself, so you always give the path.

Note: The import changes the settings in place and does not ask for confirmation. If you want a way back, first make a copy with Export settings (see Backup, logs and diagnostics).

What is imported

Values that are missing from the file, or have a type Listen does not accept, keep their current value in Listen. Only what the file contains is applied.

AreaTaken over
AppearanceTheme, follow system theme, dark and light theme, accent colour, “use the theme’s accent”, font, zoom, album and artist background blur
SidebarItem order and visibility, playlist list, playlist folders and separator, sidebar image, queue in the sidebar, panel order
HomeThe feature carousel and which home sections are shown
Artist pagesSection order and visibility, release types, radio size, external links (Last.fm, MusicBrainz, ListenBrainz, Qobuz, Spotify)
Player barInfo items, skip buttons and their seconds, volume wheel step, open drawer, volume width, button size, the waveform slider and its options, full-screen auto-open time
PlaybackGapless mode, ReplayGain mode, preamp, fallback and clipping, audio device, extra mpv parameters, fade on pause, equalizer and its preamp, preserve pitch, sample rate, exclusive mode, compressor, transcoding, scrobble thresholds
Auto-DJEnabled, item count, timing, duplicates, strategy
LyricsFetching, following, alignment, sources, delay, local lyrics first, provider and match labels, romaji, furigana, translation settings, font sizes, gaps, padding and opacity
VisualizerThe analyzer options and custom presets (built-in preset names are skipped)
HotkeysKey bindings (which also decide what is “global”), global media keys
WindowTray, minimize and exit to tray, start minimized, window bar style and track info
DiscordEnabled, application ID, “listening” mode, paused state, state icon, server image, display type, link type
ScrobblingMinimum mode, notify on song change
RemoteEnabled, port, user name
Query builderYour custom smart-playlist tags

What is not imported

  • Servers and sign-ins. Add your servers in Listen as usual (see Connecting your music).
  • Passwords. The remote-control password in the file is ignored.
  • Hotkeys you did not set in Feishin. The bindings in the file replace your current ones; actions the file does not list keep Listen’s defaults.
  • Settings that only exist in one app. Anything Feishin has and Listen does not, and the other way round, is left alone.

Note: If the file contains a lyrics translation API key, it is imported with the other lyrics settings and kept in Listen’s config.toml. Delete it in Settings if you do not want it there.

Listen’s own export is different

Settings → Advanced → Settings backup writes and reads Listen’s own format. If you give such a file to Import settings and it turns out to be a Feishin file, Listen tells you to use Import from Feishin instead. The other way round, the Feishin import expects Feishin’s layout and does not read Listen’s export.

See also Themes and colours for the Feishin themes that come with Listen.

Backup, logs and diagnostics

This page covers saving and restoring your settings, the log files, the diagnostics file you attach to a bug report, and the caches Listen keeps. All of it is in Settings → Advanced.

Settings export and import

Settings → Advanced → Settings backup

  • Export settings writes all settings to a JSON file named listen-settings-<date>-<time>.json in your Downloads folder. If a file with that name exists, a number is added. A message shows the full path. Keys that look like secrets (password, token, cookie, API key and similar) are left out. The optional Last.fm key for Discord covers is the exception: it is a plain setting and is exported.
  • Import settings reads such a file. Type or paste the path (for example ~/Downloads/listen-settings.json) and press Import.

Before anything changes, Listen checks every value and shows a confirmation: “N settings will replace your current ones. Servers and sign-ins are not touched.” If some values could not be used, the dialog lists the first six of them, each as setting.path: reason, and says they keep their current value. Typical reasons are a value of the wrong type, a setting that does not exist in this version (“unknown setting”), or a secret (“secrets are not imported”). Confirm to apply the rest, or cancel to leave everything as it is.

What is covered and what is not:

IncludedNot included
Every setting in the app: appearance, playback, hotkeys, lyrics, DJ, window, integrations, CD ripping, and so onServers and sign-ins, passwords and tokens, the Gemini key, the MCP token, listening history, queue, playlists (those live on your servers)

Importing works across machines and between Linux and Windows, so it is also the way to move your setup to a new computer: export, copy the file, import, then add your servers again.

If you give Listen a Feishin export here, it tells you to use Import from Feishin instead. See Importing from Feishin.

Note: Your servers and a few machine-specific values are kept in config.toml; see Files and folders if you want to back up the whole configuration by copying files.

Log files

Settings → Advanced → Logging

Listen writes a log while it runs, so you can find out why a song did not play.

FileContent
listen.logWhat Listen itself does: connections, playback decisions, errors
mpv.logWhat the audio player (mpv) says
rip-<date>-<disc id>.logOne per CD rip (Linux)

The logs are in the logs folder of Listen’s data folder: ~/.local/share/listen/logs on Linux and %APPDATA%\Listen\data\logs on Windows. At each start the previous run is kept as listen.log.1 and mpv.log.1, so a crash does not erase its own log. The row Log level shows the exact folder.

Log level has two choices, and the change takes effect immediately without a restart:

  • Debug (the default) records everything Listen’s own parts say. Use it when something does not work.
  • Info records less detail and keeps listen.log smaller.

Cookies and stream URLs are not written to the logs, and obvious secrets are removed again when you export diagnostics.

If you start Listen from a terminal, it also prints log lines there. Set the environment variable RUST_LOG (for example RUST_LOG=debug) to change how much; see Command line.

Export diagnostics

Settings → Advanced → Logging → Export diagnostics

Press Export and Listen saves listen-diagnostics-<date>-<time>.zip in your Downloads folder. Attach it to a bug report; see Troubleshooting. It contains:

File in the zipContent
versions.txtListen version, operating system and architecture, how Listen was installed, update channel, log level, and the first line of mpv --version and yt-dlp --version (“not found” if missing)
config.tomlYour configuration with sensitive values replaced
logs/…The last 4 MB of each log file (listen.log, listen.log.1, mpv.log, rip-*.log, and so on)

Before anything goes into the zip, Listen removes:

  • values of keys such as password, token, secret, API key, cookie, authorization, signature, salt and credentials;
  • the user name, e-mail and key fields in config.toml;
  • the login part of URLs (https://user:pass@host becomes https://***@host);
  • Authorization: Bearer … headers and common token formats (for example GitHub, Google API keys and Tailscale keys);
  • sensitive query parameters such as t, s, u, p, key, sid and auth.

Server addresses, song and artist names and file paths in the logs are not removed, and neither is the optional Last.fm key of the Discord settings if you entered one. Open the zip and look through it before you share it, and send it only to people you trust with that information.

Caches

Settings → Advanced → Cache

Caches are copies of data Listen can fetch or compute again. Clearing them is always safe: your library, playlists and settings are not touched.

RowWhat it holdsFolder in the cache directory
Clear memory cacheCovers and data kept in memory. They load again as you browse. Files on disk stay.(memory only)
Cover art cacheDownloaded album and artist imagescovers
YouTube Music audio cacheSongs kept so they can play gapless and replay quicklyytm-audio
Waveform cacheThe waveforms for the player bar sliderwaveforms

Each row shows how much space it uses. Clear asks for confirmation and then shows how many files and how much space were freed. Clear all clears the three disk caches at once, and Refresh sizes measures them again. After clearing the YouTube Music audio cache, songs you played before are fetched again when you next play them.

The cache folder is ~/.cache/listen on Linux and %LOCALAPPDATA%\Listen\cache on Windows. Other folders in it (the beat-detection model, AI DJ clips, downloaded updates, CD-rip work files) are managed by Listen itself and are not listed here. The full layout is in Files and folders.

Privacy and security

Listen has no server of its own. This page lists what leaves your computer, where it goes and why, how secrets are stored, and what you can turn off. The short version: no telemetry, no analytics and no account with the project. Listen talks only to the servers and services you set up, plus the ones listed below.

What goes where

DestinationWhenWhat is sent
Your music servers (Navidrome, OpenSubsonic, Jellyfin)Whenever you use themYour login, browsing and search requests, stream requests, favourites and ratings, playlist changes, and play reports (“scrobbles”) so the server knows what you listened to. What the server does with them (for example forwarding to Last.fm) is up to the server.
YouTube MusicOnly if you add a YouTube Music sourceRequests to YouTube Music for your library, search and playback, made with the session cookies of the browser you picked. The helper program yt-dlp contacts YouTube to find the audio stream. Cookies are read from your browser at each start and go only to YouTube. See YouTube Music.
Lyrics providersWhen lyrics are shown and lyrics fetching is on (default)Song title and artist, for some providers also album and length, to the providers you enabled in the lyrics settings: lrclib.net and NetEase by default, Genius and SimpMusic if you add them. Lyrics stored in your files or on your server are used first if you ask for that.
Translation servicesOnly if you switch on lyrics translation and enter your own keyThe lyrics text, to Microsoft Azure Translator or Google Cloud Translation, whichever you choose.
Your vocab-hub (Lute)Only if you enter its address in the lyrics settingsReads your Lute word list. With WORDS on or the Learnable songs mix open: the Korean words of the songs’ lyrics, to count which ones you know. Listen never writes to Lute.
Google GeminiOnly with the AI DJ turned on and your own keySong titles and artists the DJ picks from (with the listening history on: how often and how long ago you played each of them), the DJ’s spoken lines, your “Details for the DJ” and your requests from “Tell the DJ”. With Gemini as lyrics translation provider or with WORDS in the lyrics view: the song’s lyrics lines (for translation only the non-Latin lines). With the full-screen About tab open: the playing song’s title, artists, album and year, which Gemini looks up with Google Search. Outside the EU, UK and Switzerland, Google may use free-tier requests to improve its products; see AI DJ.
MusicBrainz, Cover Art Archive, iTunesOnly when you rip a CD (Linux)The disc’s table of contents and ID to MusicBrainz; the release to the Cover Art Archive; if that has no cover, a search by album and artist to the iTunes Search API. See CD ripping.
MusicBrainzWith the full-screen About tab open and a Gemini key setThe playing song’s title and first artist (a search), or its MusicBrainz recording id, to read the credits.
Last.fmOnly if you enter a Last.fm API key in the Discord settingsArtist and album, to look up a cover for your Discord status.
DiscordOnly with Discord Rich Presence on (Settings → Window)Song title, artist and album, play state and time, shown on your Discord profile, through the Discord app running on your computer. A server cover is sent only if you enable that option and your server is on a public address. See Discord status.
GitHubUpdate checks (default: at start), and when you press Check now or install an updateA request for the project’s public releases. No account and no personal data besides what any web request reveals (your IP address and the Listen version in the user agent). Downloads are verified against the release’s SHA256SUMS. Listen also downloads the beat-detection model for song analysis once, about 11 MB, from GitHub.
Artist link buttonsWhen you click oneOpens the browser at Last.fm, MusicBrainz, ListenBrainz, Qobuz or Spotify. Listen itself sends nothing.

Anything not in this table does not leave your computer. Music from your servers goes straight to your computer, not through anyone else.

You can turn off lyrics fetching, update checks, Discord, the AI DJ, song analysis and CD ripping individually in Settings.

What stays on your computer

  • Listening history. Songs, server and time are saved in a file on your computer and never uploaded or shared. Switch Record listening history off or use Don’t record this session in Settings → Advanced → Listening history. You can export or delete the history there. See History, statistics and mixes.
  • New from your artists. With Merge with other devices on, Home asks your own listen-server for the new releases it found. The server reads the YouTube Music pages of the artists you follow and play most, with the YouTube Music session the phone shared with it; nothing goes anywhere else. See Home.
  • Describe it. The description you type on the search page goes to your own listen-server only. The listen-embed job (only if you run it) sends the artist and title of each analysed song to Gemini once for search tags, with your Gemini key, and fetches a 30-second clip of each song from YouTube Music or your Navidrome server; see Search.
  • Song analysis results (tempo, key, sections) are stored locally, or in a folder you choose and sync yourself.
  • Settings, queue and caches are plain files in Listen’s folders; see Files and folders.

Passwords, tokens and keys

Passwords, tokens and API keys are not stored in config.toml. They go to:

  1. The system keyring: Secret Service (for example KDE Wallet or GNOME Keyring) on Linux, Windows Credential Manager on Windows.
  2. A credentials file, credentials.toml in the config folder, when no keyring is available or it refuses a value. On Linux only your user can read it (permissions 0600); on Windows it lives in your user profile.

Settings → General → Servers → Password storage shows which is in use and lets you choose System keyring or File only. Switching moves the stored secrets. The file stores secrets in plain text, protected only by the permissions of your account, so prefer the keyring when you have one. If the keyring does not work, see Troubleshooting.

The Gemini key, the MCP token and the remote-control password are stored the same way. The optional Last.fm key and the lyrics translation key are plain settings in config.toml; keep that in mind before you share the file.

Logs and diagnostics

Log files stay on your computer. Cookies and stream URLs are not written to them. When you export diagnostics, Listen also removes passwords, tokens, cookies, keys and the login part of URLs. Server addresses and song names in the logs are not removed. Nothing is uploaded; you decide whom to send the zip to. Details: Backup, logs and diagnostics.

Letting other programs and devices in

Listen has two small servers, both off by default. Turn on only what you use.

FeatureAddressProtection
Remote control (phone page and Feishin-compatible remote)Port 4333, by default on every network interfaceOptional user name and password. With both empty, anyone on your network can control Listen. Set a password or change the address to 127.0.0.1.
MCP server (AI assistants such as Claude Code or Claude Desktop)http://127.0.0.1:4334/mcp, this computer only unless you switch on Allow other computersA secret token that every request must carry. Anything holding the token can control Listen fully, including settings, your playlists on your servers and your Gemini quota. New token disconnects all clients.

Neither server returns passwords, cookies, API keys or the token itself. See Remote control and MCP server. Neither should be exposed to the internet.

Single instance and local sockets

Listen runs once per user. A second start talks to the first through a local socket (Linux: in $XDG_RUNTIME_DIR) or lock file (Windows) and exits. The audio player mpv is controlled through a private local socket. Neither is reachable from the network.

Reading browser cookies (YouTube Music)

To sign in to YouTube Music, Listen reads the cookies of youtube.com and music.youtube.com from the browser profile you pick, and only then. It stores which profile and channel to use, not the cookies. Because this looks unusual to some antivirus programs, they may warn about Listen on Windows; see Troubleshooting.

YouTube Music support is unofficial and not affiliated with Google or YouTube. You use your own account at your own risk.

Reporting a security problem

If you find a security issue, report it privately to the maintainers through the project’s GitHub page rather than in a public issue.

Troubleshooting

Answers to the problems people run into most. Each entry says what to check and, where it helps, which log to look at. The location of the logs is in Where are the logs? and the steps for a bug report are at the end.

YouTube Music songs stop playing

YouTube Music support is unofficial. It relies on the separately installed program yt-dlp to find the audio stream, and YouTube changes its site often enough that an old yt-dlp stops working. The most common cure is to update the helper programs:

  • Windows: open Settings → Advanced → Updates → Helper programs and press Update. This updates mpv, yt-dlp and Deno with winget. Show lists what is installed.
  • Linux: update yt-dlp with the way you installed it, for example sudo dnf upgrade yt-dlp, or pipx upgrade yt-dlp, or yt-dlp -U for a standalone copy. Check with yt-dlp --version.

Then try the song again. If it still fails:

  • yt-dlp needs a JavaScript runtime for YouTube. Install Deno or Node.js (Linux: sudo dnf install nodejs). The message “yt-dlp … needs a JavaScript runtime” means it is missing.
  • Run listen --check-youtube-music in a terminal. It signs in the way the app does, prints what Listen sees of your library (counts only) and tells you which step fails. See Command line.
  • Look at listen.log (see below) for lines about yt-dlp.
  • If the yt-dlp program lives in an unusual place, set the environment variable LISTEN_YTDLP to its full path.

YouTube may also restrict accounts it sees accessed by unofficial clients, or change things so that Listen has to be updated. See YouTube Music for what to expect.

YouTube Music sign-in says the browser is locked

On Windows a running browser keeps its cookie file locked. Close the browser completely (check the system tray and Task Manager for background processes) and pick it again in Listen. Listen reads the cookies when you select the browser, so you can start it again right afterwards.

Chrome, Edge or Brave on Windows cannot be used

Recent versions of Chrome, Edge and Brave on Windows protect their cookies with app-bound encryption, which only the browser itself can read. Listen then says “this browser protects its cookies with app-bound encryption (v20)”. Use Firefox instead, or choose Other ways to connect → cookies file and load a cookie export of music.youtube.com made with a browser extension. Listen’s login page also accepts such a file dropped onto it.

No sound, or “mpv” is missing

Listen plays through mpv.

  • If you see “could not start mpv; is the mpv package installed?” or “The audio player (mpv) stopped unexpectedly”, install mpv. Linux: sudo dnf install mpv (the Fedora package of Listen already depends on it). Windows: the helper programs dialog installs it, or run winget install shinchiro.mpv.
  • If mpv is installed somewhere unusual, enter its path in Settings → Playback → mpv → Executable path and press Reload. The environment variable LISTEN_MPV does the same for one run.
  • Check the output device in Settings → Playback (the audio device list) and try System default.
  • Extra parameters you or an imported Feishin file added can break mpv. Clear them and press Reload mpv.
  • Look at mpv.log next to listen.log.

Windows SmartScreen or antivirus warns about Listen

The installer is not code-signed yet, so SmartScreen says the app is unrecognised. Click More info → Run anyway. Some antivirus programs also flag Listen because it can read a browser’s YouTube sign-in; it only reads the cookies of youtube.com and music.youtube.com, only when you pick a browser, and sends them only to YouTube. If your antivirus quarantines the program, restore it and add an exception. You can check the download against the SHA256SUMS file on the project’s releases page.

Keyring unavailable

Settings → General → Servers → Password storage says where your passwords are kept. If no Secret Service keyring is running (typical on minimal desktops and some window managers), Listen falls back to a private credentials.toml in its config folder and logs “keyring unavailable”. Everything keeps working. To avoid the warning or to decide yourself, install and start a keyring (KDE Wallet with the Secret Service interface, GNOME Keyring or KeePassXC), or choose File only. Switching moves your stored passwords. If a server keeps asking you to sign in again after a restart, the keyring probably refused to give the password back; choose File only to rule that out.

Global shortcuts and media keys on Linux

  • Media keys normally work through MPRIS. KDE Plasma, GNOME, Cinnamon and Budgie send them to Listen themselves; Global media hotkeys is only needed on other desktops.
  • Global hotkeys use the desktop’s shortcut portal (KDE Plasma and GNOME). The desktop has the last word: it may ask you to confirm the keys, may pick other keys than the ones you suggested, and shows them in its own shortcut settings. If it refuses, the Hotkeys page says “The desktop refused system-wide shortcuts” with the reason. Make sure the portal for your desktop (for example xdg-desktop-portal-kde) is installed and running, then restart Listen.
  • On Wayland, apps cannot read or set their own window position, so Listen does not restore it and starts where the compositor puts it. Hiding to the tray closes the window and opens a new one when you bring it back. If you need X11 behaviour, start Listen with WINIT_UNIX_BACKEND=x11.
  • In the tray, if your desktop has no tray (some GNOME setups need an extension), Listen starts with a window instead of hidden.

See Hotkeys and Media keys and system controls.

The visualizer shows nothing

On Linux the visualizer listens to Listen’s own audio through PipeWire (pw-record and pw-dump). Check that:

  • PipeWire and its tools are installed (Fedora: pipewire-utils) and that pw-record --version works. With plain PulseAudio or ALSA there is nothing to capture.
  • Something is playing. The bars follow Listen’s output only, not other programs.
  • For the Milkdrop style, the projectM library is installed; without it only the bar styles are available. If Milkdrop shows a black picture, set LISTEN_MILKDROP_EGL to device, surfaceless or default to force one way of creating the graphics context.

For a detailed trace set LISTEN_VIZ_DEBUG=1 and read listen.log. See Visualizer and Milkdrop.

The AI DJ stopped talking or says the quota is used up

The AI DJ uses your own Gemini key, and the free tier allows only a limited number of spoken breaks per day. When Google reports the quota as used up, the DJ keeps choosing songs and shows its lines as text, and tries speech again within the hour. The AI DJ settings show “N of M spoken breaks left today”. The counter resets once a day, at midnight Pacific Time.

To get more speech, let the DJ talk less often (Talk after, Songs per set), lower Spoken breaks per day, or use a key from a project with billing enabled. If the DJ is unavailable altogether, check that the key is saved (press Save again, Listen checks it), that you are online, and that the key has not been deleted in Google AI Studio. listen --check-ai-dj runs two test rounds from a terminal. See AI DJ and Creating a Gemini API key.

Song analysis is slow or uses too much CPU

Analysis (tempo, key and sections for the DJ features) runs in the background at low priority. A large library takes hours the first time, and the results are kept, so it only happens once. To speed it up or slow it down, open the analysis settings in Settings → Playback:

  • Whole library off: only the queue is analysed.
  • Also on battery off (the default): analysis pauses when your laptop is unplugged.
  • The number of analysis threads is not in the settings window. It is threads under [settings.analysis] in config.toml: 0 (the default) uses about a quarter of your processor cores, any other number sets the count, up to the number of cores. Restart Listen after changing it.
  • Analysis folder: results are stored in Listen’s data folder unless you pick a (synced) folder. A folder on a slow network share slows things down.

The first run also downloads a small model file (about 11 MB). Without internet access Listen uses a simpler built-in tracker. You can also run listen --analyze-library --jobs 4 in a terminal to analyse the Navidrome library outside the app. See Song analysis.

CD ripping does not start

Run listen --check-cd. It names the missing tools (whipper, flac, metaflac, cd-paranoia, cdrdao), a drive that is not found, an unknown read offset, a music folder that is not mounted or not writable, and an unreachable Navidrome server. See CD ripping.

Lyrics, covers or a server do not load

  • Self-signed certificate on your server: edit the server and turn on Ignore certificate errors, which applies to that server only.
  • Wrong time or a proxy can also break secure connections.
  • Press Clear all under Settings → Advanced → Cache to drop broken cached images.
  • Look in listen.log for the failing address.

Listen is “already running”

Listen allows one copy per user. A second start brings the first window forward and exits. If the first one is hidden in the tray, use the tray icon. If you see no window and no tray icon, end the listen process in your task manager or with pkill listen and start again.

Where are the logs?

In the logs folder of Listen’s data folder:

SystemFolder
Linux~/.local/share/listen/logs/
Windows%APPDATA%\Listen\data\logs\

Settings → Advanced → Logging shows the exact path. listen.log and mpv.log are rewritten at each start; the previous run is kept as listen.log.1 and mpv.log.1. More in Backup, logs and diagnostics.

How to report a bug

  1. Reproduce the problem once with Settings → Advanced → Logging → Log level set to Debug (the default).
  2. Right after it happened, open Settings → Advanced → Logging and press Export diagnostics. Do this before restarting Listen if you can, so the log of the failing run is the current one (a restart moves it to listen.log.1, which is also included).
  3. Open the zip and read through it. Passwords, cookies and tokens are removed, but server addresses and song names are not.
  4. Open an issue on the project’s GitHub page. Say what you did, what you expected and what happened, your Listen version (Settings → About), your operating system and desktop, and attach the zip.
  5. For YouTube Music problems also include the output of listen --check-youtube-music and yt-dlp --version.

Settings

This page lists every setting on the Settings page, tab by tab and section by section, in the order they appear. For each row you get what it does, its default, and its key in config.toml.

How to read this page

  • Open the Settings page from the sidebar. The tabs are General, Playback, Hotkeys, Window, Advanced and About. The search box at the top filters the rows of all tabs by name and description. Reset to default restores the settings after asking for confirmation.
  • Settings are saved in config.toml in Listen’s config folder (see Files and folders). All keys below are written as paths from the top of that file; for example settings.ai_dj.location is the key location in the table [settings.ai_dj].
  • Values written like "single" are the exact text stored in the file. Sliders are stored as plain numbers.
  • Missing keys fall back to their defaults, so a hand-edited file only needs the keys you change. Edit the file while Listen is closed, or Listen may overwrite your change.
  • Secrets (server passwords, the remote password, the MCP token, the Gemini API key) are kept in the system keyring or a restricted file, not in these keys.
  • Rows marked Linux or Windows only are hidden on the other system. Some rows only appear when another option is on, or when the connected server supports the feature.

General

Servers

Lists your music sources with the buttons Switch (shown as Browsing for the active one), Rescan (local folders), Edit, Remove and Add server. See Connecting your music. Servers are stored in the [[servers]] tables, not under settings.

RowWhat it doesDefaultKey
Password storageWhere passwords are kept: System keyring, or File only (a file only you can read). The row says which one is in use.System keyringsecret_store ("auto" or "file"; top level)

Scrobble

RowWhat it doesDefaultKey
ScrobbleReports plays to the server and, when connected, to Last.fm. Nothing is reported in private mode.Onsettings.playback.scrobble
Last.fmAPI key and shared secret of your Last.fm API account, Connect to Last.fm / Disconnect. The secret and the sign-in are kept in the keyring.not connectedsettings.integrations.lastfm.api_key, settings.integrations.lastfm.user
Scrobble to Last.fmSends plays to Last.fm while connected.Onsettings.integrations.lastfm.scrobble
Scrobble minimum modeWhen a play counts: Percentage or seconds (whichever comes first), Percentage, or Seconds. Skipping ahead does not count as listening.Percentage or secondssettings.integrations.scrobble_mode ("both", "percentage", "seconds")
Minimum scrobble percentageThe share of the song that has to be played, 25 to 90 %. Hidden in Seconds mode.75settings.playback.scrobble_at_percent
Minimum scrobble secondsThe time that has to be played, 0 to 1200 s in steps of 5. Hidden in Percentage mode.240settings.playback.scrobble_at_secs
Song change notificationsShows a desktop notification with the song, artists, album and cover when the song changes.Offsettings.integrations.notify_song_change

Appearance

See Themes and colours for details.

RowWhat it doesDefaultKey
Follow desktop themeLinux only. Uses the KDE colour scheme and follows changes live. Takes precedence over the theme choices.On (Linux)settings.appearance.follow_desktop_theme
Follow system themeUses the dark or light theme below depending on the desktop’s setting.Onsettings.appearance.follow_system_theme
Dark themeShown when Follow system theme is on. Used when the desktop is dark.Tokyo Nightsettings.appearance.theme_dark ("tokyoNight")
Light themeShown when Follow system theme is on. Used when the desktop is light.Default Lightsettings.appearance.theme_light ("defaultLight")
ThemeShown when Follow system theme is off. The theme that is always used.Default Darksettings.appearance.theme ("defaultDark")
Use the theme’s accent colourOn: the theme keeps its own accent. Off: your accent colour replaces it.Offsettings.appearance.use_theme_accent
Accent colourFive swatches and a field for a CSS colour such as rgb(53, 116, 252) or #3574fc. Disabled while the previous row is on.rgb(53, 116, 252)settings.appearance.accent
Use the theme’s primary shadeOn: buttons and links use the theme’s shade.Onsettings.appearance.use_theme_primary_shade
Primary shade0 (lightest) to 9 (darkest) shade of the accent for buttons and links. Used when the previous row is off.6settings.appearance.primary_shade
Custom themes folderShows how many custom themes were found and any problems; Open folder opens the folder. See Custom themes.
Touchpad scroll speed25 to 200 % in steps of 5. At 100 %, a swipe scrolls as far as in Chromium-based browsers.100 %settings.appearance.scroll_speed (1.0 = 100 %)

Application

RowWhat it doesDefaultKey
Font typeBuilt-in, System or Custom.Built-insettings.appearance.font_kind ("builtin", "system", "custom")
FontBuilt-in: Inter or Poppins. System: any installed font. Used for all text.Intersettings.appearance.font
Font fileCustom only. Path to a .ttf, .otf or .ttc file; press Use to apply.emptysettings.appearance.font_path
LanguageThe interface language. Applies after a restart. See Languages.System defaultsettings.appearance.language ("" or a code such as "de")
ZoomScales the interface, 50 to 300 % in steps of 5, with -, + and Reset. Applies when you let go of the slider.100 %settings.appearance.zoom
Album background imageBlurred cover behind album page headers; the slider sets the blur (0 to 6).On, 3.0settings.appearance.album_background, settings.appearance.album_background_blur
Artist background imageThe same for artist pages.On, 3.0settings.appearance.artist_background, settings.appearance.artist_background_blur
Blur explicit imagesBlurs the covers of songs tagged explicit.Offsettings.appearance.blur_explicit_images
Native cover aspect ratioShows covers whole instead of cropped square; wide covers make their card shorter.Offsettings.appearance.native_cover_aspect
Image placeholderWhat a cover shows while loading: ThumbHash, Colour or Off.Coloursettings.appearance.image_placeholder ("thumbHash", "dominantColor", "off")

Home

RowWhat it doesDefaultKey
Home featured carouselShows the large featured carousel at the top of the home page.Onsettings.home.feature
Home featured carousel styleSingle or Multiple featured albums.Singlesettings.home.feature_style ("single", "multiple")
Home sectionsTick the sections to show and drag them into order.Genres, Most played, Random, Recently added, Recently played, Recently released, Playlistssettings.home.sections (list of ids such as "mostPlayed")

Player bar

RowWhat it doesDefaultKey
Player bar button sizeSize of the player bar buttons, 15 to 30 px.15settings.player_bar.button_size
Show skip buttonsShows the skip-backward and skip-forward buttons.Onsettings.player_bar.skip_buttons
Skip backward durationSeconds to jump back, 0 to 120.5settings.player_bar.skip_backward_secs
Skip forward durationSeconds to jump ahead, 0 to 120.10settings.player_bar.skip_forward_secs
Volume slider widthWidth of the volume slider, 25 to 300 px.70settings.player_bar.volume_width
Volume wheel stepVolume change per mouse-wheel notch on the slider, 1 to 20.5settings.player_bar.volume_wheel_step
Player bar opens full-screen playerA click on the empty area of the player bar opens the full-screen player.Offsettings.player_bar.open_drawer
Expand album art buttonShows the expand button on the player bar’s cover. Turning it off also collapses the sidebar image.Onsettings.sidebar.show_image
Show remaining timeShows the time left instead of the duration (a click on the duration also switches).Offsettings.player_bar.show_time_remaining
Right-hand buttonsTick the buttons to show and move them with the arrows: Sleep timer, Player config, Visualizer, Lyrics, Favorite, Queue, Volume.All shown, in that ordersettings.player_bar.right_controls (list of id and visible)
Playerbar sliderSlider or Waveform as the seek bar. The waveform is not recommended on a slow or metered connection.Slidersettings.player_bar.slider_type ("slider", "waveform")
Waveform alignWaveform only. Top, Center or Bottom.Centersettings.player_bar.waveform_align
Waveform bar widthWaveform only. 1 to 10 px.2settings.player_bar.waveform_bar_width
Waveform gapWaveform only. 0 to 10 px.1settings.player_bar.waveform_gap
Waveform radiusWaveform only. Rounding of the bars, 0 to 20 px.4settings.player_bar.waveform_radius
Waveform stretchWaveform only. Stretches the waveform to fill the available space.Offsettings.player_bar.waveform_stretch
Waveform loading delayWaveform only. Seconds to wait before the waveform of a new song is computed, 0 to 10. Raise it if you notice stutters when songs change.2settings.player_bar.waveform_delay_secs

The metadata badges under the title in the full-screen player (codec, bit rate and so on) are chosen in the full-screen player’s Configure dialog and stored in settings.player_bar.info_items (default ["codec", "release_year"]).

Full-screen player

See Full-screen player and Now Playing.

RowWhat it doesDefaultKey
Full-screen auto-open timeoutOpens the full-screen player after this many minutes without input while a song plays. 0 turns it off. Range 0 to 120.0 (off)settings.fullscreen.auto_open_minutes
ConfigureOpens a dialog with the options below.

The Configure dialog:

OptionWhat it doesDefaultKey
Dynamic backgroundBackground from the cover’s average colour; off uses the theme background.Onsettings.fullscreen.dynamic_background
Use the cover as backgroundUses the blurred cover instead of a flat colour.Offsettings.fullscreen.dynamic_is_image
Image blurBlur of that image, 0 to 6 rem.6settings.fullscreen.image_blur
OpacityDarkening over the background, 0 to 100 %.25settings.fullscreen.opacity
Use the cover’s aspect ratioKeeps the cover’s shape instead of a square.Offsettings.fullscreen.use_image_aspect_ratio
Cover sizePercent of its column, 55 to 100.75settings.fullscreen.cover_size
AlignmentLeft, Center or Right.Centersettings.fullscreen.alignment
TitleScrolling (one line that scrolls) or Wrapped.Scrollingsettings.fullscreen.title_display ("scroll", "multi_line")
Title linesLines of a wrapped title, 1 to 10.1settings.fullscreen.title_lines
RowWhat it doesDefaultKey
Sidebar configurationTick the items to show and drag them into order. Items: Now playing, Search, Home, Favorites, Albums, Tracks, Album artists, Artists, Genres, Folders, Playlists, Collections, Recently played, Statistics, Mixes, Radio, Settings.All shown except Now playing, Search, Playlists and Settingssettings.sidebar.items (list of id, label, visible)
Sidebar playlist listShows the playlist list in the sidebar.Onsettings.sidebar.show_playlists
Playlist filter regexHides playlists whose name matches this regular expression (case-insensitive). An invalid expression hides nothing.emptysettings.sidebar.playlist_filter_regex
Sidebar playlist sortingLets you sort playlists by drag and drop instead of the server order.Offsettings.sidebar.playlist_sorting
Sidebar playlist modeCompact (name only) or Expanded (cover, name and song count).Expandedsettings.sidebar.playlist_mode ("compact", "expanded")
Enable foldersGroups playlists whose names contain the separator into folders.Offsettings.sidebar.playlist_folders
Folder separatorShown when folders are on. The character or text that separates folder levels./settings.sidebar.playlist_folder_separator
Folder viewShown when folders are on. Single folder, Tree view or Navigation view.Tree viewsettings.sidebar.playlist_folder_view ("single", "tree", "navigation")
Tree indentTree view only. Pixels per level, 0 to 64.16settings.sidebar.folder_tree_indent
Tree line colorTree view only. Colour of the guide lines as #rrggbb; empty uses the theme.emptysettings.sidebar.folder_tree_line_color
Sidebar (collapsed) navigationShows the navigation in the collapsed sidebar.Onsettings.sidebar.collapsed_navigation

Lists

RowWhat it doesDefaultKey
Play button behaviorWhat the Play buttons, a double-click on a song and the play hotkey do: Play now, Add to queue next, Add to queue last. Shuffle play and the DJs are not affected.Play nowsettings.lists.play_behavior ("now", "next", "last")
Grid multi-selectClicking a card’s cover selects it. Off: it opens the item.Onsettings.lists.grid_multi_select
Show favouritesShows heart buttons and favourite columns everywhere.Onsettings.lists.show_favorites
Show ratingsShows star ratings (Navidrome, OpenSubsonic) on tracks, albums and artists.Onsettings.lists.show_ratings

How each list looks (table, grid, columns) is changed in the list itself and stored under settings.lists.lists.

Artist page

RowWhat it doesDefaultKey
Artist page configurationTick the sections to show and move them with the arrows: Biography, Favorite songs, Recent releases (always shown, only its place changes), Related artists, Top songs.All on, in that ordersettings.artist.items (list of id, enabled)
Artist release type configurationTick the release types to show and order them as groups: Appears on, Album, Audio drama, Audiobook, Broadcast, Compilation, Demo, DJ-mix, EP, Field recording, Interview, Live, Mixtape / street, Other, Remix, Single, Soundtrack, Spoken word.All onsettings.artist.release_types
Artist radio countNumber of songs an artist radio queues, 1 to 100.20settings.artist.radio_count
RowWhat it doesDefaultKey
External linksShows links to other sites on artist and album pages. The rows below appear when it is on.Onsettings.artist.external_links.enabled
Last.fmLink to the artist or album on Last.fm.Onsettings.artist.external_links.last_fm
MusicBrainzLink on MusicBrainz, only where the server knows the MusicBrainz id.Onsettings.artist.external_links.music_brainz
ListenBrainzLink on ListenBrainz.Onsettings.artist.external_links.listen_brainz
QobuzSearch link on Qobuz.Onsettings.artist.external_links.qobuz
SpotifySearch link on Spotify.Onsettings.artist.external_links.spotify
Open in the Spotify appOpens the Spotify link in the desktop app instead of the web player.Offsettings.artist.external_links.native_spotify

Query builder

Shown only when the connected server supports smart playlists.

RowWhat it doesDefaultKey
Custom fieldsAdds your own fields for the smart-playlist builder. Each has a label, a type (string, number, boolean, date, playlist) and a tag.nonesettings.query_builder.tags

Sharing

RowWhat it doesDefaultKey
Use the server’s default expirationNew share links get no expiry date from Listen; the server decides.Offsettings.sharing.expiration.use_server_default
Default share expirationHow long a new share link works: a number and a unit (second, minute, hour, day, week, month, year). You can change it for each share.1 yearsettings.sharing.expiration.amount, settings.sharing.expiration.unit ("year")

Playback

Playback

RowWhat it doesDefaultKey
Audio playerOnly shown when the server offers a jukebox. mpv plays on this computer; Jukebox plays the queue through the server’s speakers while this computer only controls it.mpvsettings.playback.audio_player ("mpv", "jukebox")
Gapless playbackmpv’s gapless-audio: weak, yes or no.weaksettings.playback.gapless
Streaming qualityCaps the bit rate: Original, High (320 kbit/s), Normal (192), Low (96). Navidrome transcodes to MP3; YouTube Music picks a smaller format. Downloaded songs stay original.Originalsettings.playback.stream_quality ("original", "high", "normal", "low")
Fade songs in and outEach song fades in at its start and out at its end, 0 to 10 s in half-second steps (0 is off). The AI DJ uses the same speed for turning the music down and up (at least 1 s).1.5 ssettings.playback.track_fade_secs
Fade on pauseFades out briefly when pausing and back in when resuming.Onsettings.playback.fade_on_pause
Prefer my own servers for YouTube Music songsOnly shown with a YouTube Music account. Plays a YouTube Music song from your Navidrome, Jellyfin or local library when it has the same song. The song stays a YouTube Music song. See YouTube Music.Onsettings.playback.prefer_own_servers
Cast to DLNA devicesLooks for DLNA / UPnP speakers and TVs on the network and shows a cast button when some answer. See Casting.Onsettings.playback.dlna_enabled

The player bar’s volume (0 to 100) is saved in settings.playback.volume (default 70).

Audio output

RowWhat it doesDefaultKey
Audio deviceThe device mpv plays on, with a Refresh button.autosettings.playback.audio_device
Preserve pitchKeeps the pitch when the playback speed changes. Off: speed also changes the pitch, and the player config offers semitone steps.Onsettings.playback.preserve_pitch
Microtonal pitch controlsAdds 10 cent steps between the semitone buttons (when the pitch is not preserved).Offsettings.playback.microtonal_pitch
Sample rateOutput sample rate in Hz; below 8000 or empty means the device’s default. Press Enter to apply.0 (device default)settings.playback.sample_rate_hz
Exclusive modeTakes the sound device for Listen alone (WASAPI and some ALSA setups).Offsettings.playback.audio_exclusive
Audio formatSample format sent to the sound card: auto, s16, s32, float, u8.autosettings.playback.audio_format (empty = auto)

Volume levelling

RowWhat it doesDefaultKey
LevelPlays every song equally loud: Off, Quiet (−19 LUFS), Normal (−14 LUFS) or Loud (−11 LUFS), from the analysis, YouTube’s loudness or ReplayGain tags, with a limiter. Replaces ReplayGain while on.Normalsettings.playback.levelling ("off", "quiet", "normal", "loud")

ReplayGain

RowWhat it doesDefaultKey
ModeNormalises loudness using ReplayGain tags: No, Track or Album (only while Volume levelling is off).Nosettings.playback.replay_gain ("no", "track", "album")
PreampGain added on top of the ReplayGain value, -15 to +15 dB.0settings.playback.replay_gain_preamp_db
Prevent clippingLowers the gain so the peak never exceeds full scale.Onsettings.playback.replay_gain_clip
Fallback gainGain for songs without ReplayGain tags, -15 to +15 dB.0settings.playback.replay_gain_fallback_db

mpv

RowWhat it doesDefaultKey
Executable pathThe mpv program to run; empty uses mpv from the PATH. Needs a reload.emptysettings.playback.mpv_path
Extra parametersOne mpv option per line, for example --audio-channels=stereo. Needs a reload.nonesettings.playback.mpv_extra_args (list)
Reload mpvStops playback and starts mpv again with the path and parameters above.

Equalizer

See Sound.

RowWhat it doesDefaultKey
EqualizerTurns the 12-band equalizer on.Offsettings.playback.equalizer_enabled
PresetsBuilt-in presets (Acoustic, Bass Boost, Bass Cut, Classical, Electronic, Flat, Hip-Hop, Jazz, Loudness, Pop, Rock, Treble Boost, Treble Cut, V-Shape and more) and your own: set the bands, type a name and save. Reset sets all bands to 0.nonesettings.playback.equalizer_preset, settings.playback.custom_eq_presets
Band slidersA preamp and 12 bands, each -12 to +12 dB in half-dB steps.0settings.playback.equalizer_preamp, [[settings.playback.equalizer]] (freq, gain)

Headphone correction

See Sound.

RowWhat it doesDefaultKey
Headphone correctionApplies the AutoEq profile bound to the output that plays now.Onsettings.playback.headphone_eq
This output / Find your headphonesThe output playing now and its profile; search the built-in AutoEq index (or paste a ParametricEQ.txt) to bind one.nonesettings.playback.headphone_profiles (output → name, source, preamp, filters)
Other outputsProfiles bound to outputs that don’t play now.nonesame

Heart-rate tempo

See Heart-rate tempo.

RowWhat it doesDefaultKey
Heart-rate tempoThe DJs pick songs whose tempo fits your heart rate from a Bluetooth heart-rate sensor (needs Bluetooth). Shows the status and the target. Not kept across restarts; the heart button in the player bar switches it too.Offnone
SensorThe sensor last connected, tried first next time; Forget sensor clears it.nonesettings.playback.heart_rate_sensor (id, name)

Compressor

RowWhat it doesDefaultKey
CompressorEvens out loud and quiet parts.Offsettings.playback.compressor.enabled
PresetsBroadcast, Default, Gentle, Heavy, Light, Limiter, Loud Master, Moderate, plus your own.nonesettings.playback.compressor_preset, settings.playback.custom_compressor_presets
ThresholdLevel above which compression starts, -60 to 0 dB.-24settings.playback.compressor.params.threshold
RatioHow strongly loud parts are reduced, 1 to 20 (n:1).4settings.playback.compressor.params.ratio
AttackHow fast it reacts, 0.1 to 2000 ms.20settings.playback.compressor.params.attack
ReleaseHow fast it lets go, 1 to 9000 ms.250settings.playback.compressor.params.release
Makeup gainGain added after compressing, 0 to 30 dB.6settings.playback.compressor.params.makeup
KneeWidth of the soft knee, 1 to 8 dB.2.83settings.playback.compressor.params.knee

Transcoding

Only shown for servers that can transcode (Navidrome, Jellyfin).

RowWhat it doesDefaultKey
TranscodeAsks the server to convert songs while streaming. Takes the place of Streaming quality for those servers. Applies to songs that start from now on.Offsettings.playback.transcode.enabled
FormatShown when on. mp3, opus, flac and so on; empty is the server’s choice (Jellyfin: mp3).emptysettings.playback.transcode.format
Maximum bit rateShown when on. In kbit/s; 0 or empty lets the server pick.0settings.playback.transcode.bitrate
Maximum sample rateShown when on. In Hz, Jellyfin only; empty is no limit.0settings.playback.transcode.max_sample_rate

Queue

See Player bar and queue.

RowWhat it doesDefaultKey
Follow current songScrolls the queue to the playing song whenever the track changes.Onsettings.queue.follow_current_song
Up next queueLabels songs added with Play next and Add to queue as Up Next. They play right after the current song, ahead of the rest of the queue and the Auto-DJ songs.Onsettings.queue.up_next_queue
Confirm queue changesAsks before playing something replaces the queue, or before clearing it.Offsettings.queue.confirm_queue_changes
Save play queueKeeps the queue and your position when Listen closes and restores them at the next start.Onsettings.queue.save_play_queue
Autosave play queue to serverSaves the queue to the server (OpenSubsonic, Navidrome) as the track changes, so another app can pick it up.Offsettings.queue.autosave_server
Autosave everyNumber of track changes between two saves, 1 to 20.1settings.queue.autosave_every
Side play queue styleAttached (a side panel) or Detached (a drawer that slides in when you rest the pointer on the right edge).Attachedsettings.queue.side_style
Side queue layoutHorizontal (a column on the right) or Vertical (a panel under the page).Horizontalsettings.queue.side_layout

Player sidebar panels

RowWhat it doesDefaultKey
Queue panelShows the play queue in the right sidebar.Onsettings.sidebar.show_queue
Lyrics panelShows the lyrics of the playing song in the right sidebar.Offsettings.queue.lyrics_in_sidebar
Visualizer panelShows the spectrum in the right sidebar (captures only Listen’s own audio).Onsettings.visualizer.in_queue_panel
Combine lyrics and visualizerShows lyrics with the visualizer under them in one panel.Offsettings.queue.combined_panel
Panel orderOrder of the panels, top to bottom, set with the arrows.Queue, Lyrics, Visualizersettings.sidebar.panel_order

Player filters

RowWhat it doesDefaultKey
Player filtersAdd rule adds a rule that keeps matching songs out of the queue when you play or queue them. Each rule has an on/off switch, a field (Title, Album artist, Artist, Duration (s), Genre, Year, Release year, Note, Path, Play count, Favorite, Rating), an operator (is, is not, contains, does not contain, starts with, ends with, is greater than, is less than, matches regex) and a value. Auto-DJ and the AI DJ are not filtered.no rulessettings.queue.filters (list of field, op, value, enabled)

Visualizer

See Visualizer and Milkdrop.

RowWhat it doesDefaultKey
In the queue panelShows the spectrum under the queue. Same switch as Visualizer panel above.Onsettings.visualizer.in_queue_panel
Visualizer settingsConfigure… opens the spectrum options: mode, gradients, channel layout, frequency scale, peaks, reflex, radial and more, plus saved presets.[settings.visualizer]

Some defaults in [settings.visualizer]: mode = 10 (line graph), gradient = "prism", fft_size = 16384, smoothing = 0.6, min_freq = 20, max_freq = 22050, min_db = -85, max_db = -25.

Milkdrop

RowWhat it doesDefaultKey
Visualizer typeSpectrum or Milkdrop (Milkdrop only when projectM is available).Spectrumsettings.milkdrop.kind ("spectrum", "milkdrop")
Preset folderFolder with .milk presets, with Browse… and Rescan; empty uses the default folder in Listen’s data folder.emptysettings.milkdrop.preset_dir
PresetSearch and pick the preset on screen.nonesettings.milkdrop.current_preset
Next presetSwitches now.
Cycle presetsSwitches preset every few seconds.Onsettings.milkdrop.cycle_presets
Cycle timeSeconds a preset stays, 1 to 300.30settings.milkdrop.cycle_time
Blend timeSeconds a preset takes to blend into the next, 0 to 10.2.5settings.milkdrop.blend_time
Random next presetPicks the next preset at random; off takes the next in the list.Onsettings.milkdrop.randomize
Include all presetsCycles through every preset; off uses only the selected ones.Onsettings.milkdrop.include_all
Selected presetsPresets to cycle through when the previous row is off.nonesettings.milkdrop.selected
Ignored presetsPresets that are never picked.nonesettings.milkdrop.ignored

Frame rate and opacity are settings.milkdrop.max_fps (0 means 30) and settings.milkdrop.opacity (0 to 1, default 1).

Auto-DJ

See Play modes and Auto-DJ.

RowWhat it doesDefaultKey
EnabledKeeps the queue going with similar songs.Onsettings.auto_dj.enabled
Songs to addSongs added whenever the queue runs out, 1 to 20.5settings.auto_dj.item_count

AI DJ

See AI DJ and Creating a Gemini API key. Everything the DJ sends to Google is listed in the section’s note: song titles, artists, the DJ’s lines and your details for the DJ. Outside the EU, UK and Switzerland, Google may use free-tier requests to improve its models.

RowWhat it doesDefaultKey
EnabledPicks sets of songs that fit the mood and talks between them like a radio host. Replaces the Auto-DJ while on.Offsettings.ai_dj.enabled
Gemini API keyYour own key, saved in the system keyring. Save an empty field to remove it.nonekeyring, not in config.toml
PersonaThe host or hosts: Late-Night, Morning Show, Calm, Hamburg Duo. Preview plays a sample (needs a key).Late-Nightsettings.ai_dj.persona ("late_night", "morning", "calm", "hamburg_duo")
Voice modelFlash-Lite TTS (fast) or Flash TTS (best voice acting). Both are on Gemini’s free tier; the daily speech quota is small.Flash-Lite TTSsettings.ai_dj.tts_model
Songs per setThe DJ picks 2 up to this many songs between breaks, 2 to 8.5settings.ai_dj.set_max (and set_min, 2)
Talk afterTalk after every set, or only every 2nd to 5th set (saves speech quota).1settings.ai_dj.talk_every
Voice volumeRelative to the music, -12 to +12 dB.0settings.ai_dj.voice_gain_db
LocationWhere the show airs, for example your town; the hosts mention it now and then. Empty means no home town.emptysettings.ai_dj.location
PronunciationHow the voice should say the place name if it gets it wrong.emptysettings.ai_dj.location_pronunciation
LanguageThe language the hosts speak. Same as the app or one of the 17 languages.Same as the appsettings.ai_dj.language ("" or a code)
Details for the DJAnything the hosts should know: your name, what you like, topics to avoid. Sent to Gemini with every break.emptysettings.ai_dj.notes

settings.ai_dj.text_model (default gemini-3.5-flash-lite) names the text model and has no row on the Settings page.

DJ transitions & song analysis

See Song analysis and DJ transitions.

RowWhat it doesDefaultKey
Analyse songsMeasures tempo, beats, key, energy and sections of Navidrome songs for the DJs.Onsettings.analysis.enabled
YouTube Music songsAlso analyses YouTube Music songs: Listen fetches a temporary copy of each to measure it and keeps only the results. Needs an analysis folder first. Not shown in the demo.Offsettings.analysis.youtube_music
Whole libraryWorks through the library in the background; the queue always comes first.Onsettings.analysis.analyze_library
Also on batteryKeeps analysing when the computer is unplugged.Offsettings.analysis.on_battery
Analysis folderWhere results are kept, with Save and Choose…. A synced folder lets your other computers reuse them. Empty uses Listen’s data folder.emptysettings.analysis.shared_dir
Singing-voice detectorDownload / Remove for the optional DJustify detector (2 MB, CC BY-NC 4.0). Songs analysed without it are analysed again in the background (not YouTube Music).not downloadedfile models/djustify-svdnet.pt in the data folder
DJ transitionsMixes songs the Auto-DJ or AI DJ picked: beat-matched blends, or fades when songs do not fit.Onsettings.mixing.enabled
Order by flowPicks songs whose tempo, key and energy follow on from the current one.Onsettings.mixing.flow_select
Largest tempo changeBeyond this the songs fade instead of being beat-matched, 2 to 8 %.6settings.mixing.max_tempo_pct
Long blendsLength of a blend over instrumental intros and outros: 8 or 16 bars.16settings.mixing.long_blend_bars
Transition edgesWhether vocals at a song’s end or start may be blended over: Always, Instrumental only, or Smart (relaxed for club genres such as garage, house, techno and drum and bass).Smartsettings.mixing.transition_edges ("smart", "always", "instrumental")
Transitions may skip parts of songsWhether a transition may cut the outgoing song short (after its last sung line, at a breakdown) or skip part of the next song’s intro: Free, Short (at most 16 s of either) or Never (mix in the outro, start the next song at its first beat).Freesettings.mixing.skip_parts ("free", "short", "never")
Tempo rampsGlides the tempo between songs instead of jumping.Onsettings.mixing.tempo_ramps
Bass swapSwaps the basslines on a downbeat so only one plays at a time.Onsettings.mixing.bass_swap
Mix queued songsAlso mixes into songs added with Add to queue while a DJ is on.Onsettings.mixing.mix_manual_queue
Bridge songsPlays a short instrumental part of an analysed song between two songs that are far apart and mixes through it.Onsettings.mixing.bridges
How often to bridgeShare of far-apart pairs that get a bridge when one fits, 10 to 100 %. Pairs that cannot be beat-matched (echo-out, cut or fade otherwise) always try one.50settings.mixing.bridge_chance_pct

Other keys without a row: settings.mixing.fallback_fade_secs (plain fade length, default 4) and settings.analysis.threads (0 means automatic).

Lyrics

See Lyrics.

RowWhat it doesDefaultKey
Fetch lyricsGets lyrics from the server, YouTube Music or the providers below.Onsettings.lyrics.fetch
Prefer local lyricsUses the server’s or YouTube Music’s own lyrics before the providers’. Plain ones still give way to synchronized lyrics from a provider.Onsettings.lyrics.prefer_local
Lyric providersWhich providers are asked and in which order; the first with synchronized lyrics wins. Choices: NetEase, lrclib.net, Genius, SimpMusic.NetEase, lrclib.netsettings.lyrics.sources
Lyric offsetDefault shift of the lyrics against the music, in milliseconds (the lyrics view can change it per song).0settings.lyrics.delay_ms
AlignmentLeft, Center or Right.Centersettings.lyrics.alignment
Lyric size (synchronized)Font size of timed lyrics.24settings.lyrics.font_size
Lyric size (unsynchronized)Font size of untimed lyrics.24settings.lyrics.font_size_unsync
Lyric gap (synchronized)Space between lines.24settings.lyrics.gap
Lyric gap (unsynchronized)Space between lines of untimed lyrics.24settings.lyrics.gap_unsync
Left paddingEmpty space left of the lyrics, in percent of the width.0settings.lyrics.padding_left
Right paddingEmpty space right of the lyrics, in percent of the width.0settings.lyrics.padding_right
Follow the current lyricScrolls along with the line being sung.Onsettings.lyrics.follow
Follow positionWhere the current line sits while following: -50 near the top, 0 centred, 50 near the bottom.0settings.lyrics.follow_scroll_alignment
Line lead timeA line lights up this many milliseconds before its time.800settings.lyrics.line_lead_time_ms
Opacity of other linesHow visible the lines that are not being sung are.0.2settings.lyrics.opacity_non_active
Size of other linesSize of those lines compared to the current one.0.95settings.lyrics.scale_non_active
Show the matchShows which song the provider matched.Offsettings.lyrics.show_match
Show the providerShows where the lyrics came from.Onsettings.lyrics.show_provider
RomajiShows Japanese lyrics in Latin letters under the line. Kanji are read only in builds that include the Japanese dictionary.Offsettings.lyrics.enable_romaji
FuriganaShows the reading above kanji in Japanese lyrics. Only in builds with the dictionary.Offsettings.lyrics.enable_furigana
NetEase translationsFetches NetEase’s own translation and shows it under each line.Offsettings.lyrics.enable_netease_translation
Translation languageThe language online translation translates into.Englishsettings.lyrics.translation_target_language ("en")
Translation providerNone, Microsoft Azure or Google Cloud. Needs your own API key.Nonesettings.lyrics.translation_api_provider
Translation API keyThe key of that provider. It is stored in config.toml, so keep that file private.emptysettings.lyrics.translation_api_key
Automatic translationTranslates every song’s lyrics when they load (needs the provider and key).Offsettings.lyrics.enable_auto_translation

Hotkeys

See Hotkeys for how to record keys and what the global option does.

Application hotkeys. One row per action. Click the field, press the keys (Esc cancels, the cross clears it). A key bound twice is outlined in red. On Linux, a global checkbox next to an action registers it system-wide through the desktop’s shortcut portal; it needs a key to be set first, and only some actions allow it.

RowWhat it doesDefaultKey
Each actionBrowser back / forward, Favorite / Unfavorite / Toggle favorite of the current and previous song, Global search, Local search, List: navigate to page / play (default) / play last / play next / play now / show playing song, Navigate to home, Next / Previous track, Next / Previous album, Pause, Play, Play / pause, Rate 0 to 5 stars, Skip backward / forward, Stop, Toggle full-screen player, Toggle heart-rate tempo, Toggle queue, Toggle repeat, Toggle shuffle, Volume up / down / mute, Zoom in / out.Play / pause space; Global search mod+k; Local search mod+f; List: show playing song mod+l; List: navigate to page mod+g; List: play (default) enter; all others unboundsettings.hotkeys.<action> (for example settings.hotkeys.playPause = "space")
global (Linux)Registers the action system-wide.nonesettings.hotkeys_global (list of action ids)

System-wide (Linux only):

RowWhat it doesDefaultKey
Global media hotkeysLets Listen grab the media keys through the desktop portal. Off: only MPRIS controls Listen. On KDE, GNOME, Cinnamon and Budgie the desktop already sends the keys over MPRIS, so Listen does not bind them again.Onsettings.global_media_keys

Window

Window & integrations

RowWhat it doesDefaultKey
Private modeNothing is scrobbled, shown on Discord or saved in the history, and the window title says so. Turns off again when Listen restarts.Offnot saved
Window bar styleWindows or macOS buttons in Listen’s own bar, or Native for the desktop’s frame.Windowssettings.window.custom_title_bar and settings.window.custom_bar_style ("windows", "macos"); Native sets custom_title_bar = false
Track info in window titleShows the playing song in the window bar and title.Onsettings.window.title_bar_track_info
Tray iconShows Listen in the system tray.Onsettings.window.tray
Minimize to trayShown when the tray icon is on. Minimizing hides the window in the tray.Offsettings.window.minimize_to_tray
Close to trayShown when the tray icon is on. Closing the window keeps Listen playing in the tray.Offsettings.window.exit_to_tray
Start minimizedShown when the tray icon is on. Starts with only the tray icon.Offsettings.window.start_minimized
Prevent display sleep while playingKeeps the screen on and the system awake while music plays.Offsettings.window.prevent_display_sleep
Prevent system sleep while playingKeeps the system from suspending; the screen may still turn off. Shown as on while the previous row is on.Offsettings.window.prevent_system_sleep
Discord Rich PresenceShows what you are listening to on Discord. See Discord status.Offsettings.window.discord_rpc
Discord application IDThe Discord application used for the presence. Press Enter to apply.Listen’s own applicationsettings.window.discord_client_id
Show presence when pausedKeeps the presence while paused, with the paused icon and no timer.Onsettings.integrations.discord.show_paused
Show playing iconShows the small playing icon next to the cover while a song plays.Onsettings.integrations.discord.state_icon
Show status as listeningShows “Listening to” instead of “Playing”.Offsettings.integrations.discord.show_as_listening
Discord display typeWhat the status line shows: Listen, Song name or Artist name.Listensettings.integrations.discord.display ("feishin", "song", "artist")
Discord link typeLinks the song, artist and cover to None, Last.fm, MusicBrainz or MusicBrainz (Last.fm fallback).Nonesettings.integrations.discord.link ("none", "last_fm", "music_brainz", "music_brainz_last_fm")
Show server cover imageSends the server’s cover to Discord. Only used when the server is reachable from the internet over https; the link includes your access token, so Discord and its users can see it. YouTube Music covers are always shown; local covers are never sent.Offsettings.integrations.discord.server_image
Last.fm API keyLooks up the album cover on Last.fm when no other cover is available for Discord. Press Enter to save.emptysettings.integrations.discord.lastfm_key

Remote control

See Remote control.

RowWhat it doesDefaultKey
Enable remote control serverServes a remote control page. The description shows the address while it runs, or why it did not start.Offsettings.integrations.remote.enabled
Remote server portThe port of the server. Press Enter to apply.4333settings.integrations.remote.port
Remote server address0.0.0.0 lets other devices in your network connect; 127.0.0.1 only this computer. Press Enter to apply.0.0.0.0settings.integrations.remote.bind
Remote server usernameThe user name to sign in with. Leave both fields empty for no sign-in.emptysettings.integrations.remote.username
Remote server passwordThe password to sign in with. Press Enter to save; it is kept in the keyring.nonekeyring, not in config.toml

A warning appears when the server is on without a username and password: anyone in your network can then control Listen.

MCP server

See MCP server.

RowWhat it doesDefaultKey
Enable MCP serverLets an MCP client control Listen.Offsettings.integrations.mcp.enabled
MCP server portPress Enter to apply.4334settings.integrations.mcp.port
Allow other computersOff: only programs on this computer can connect. On: anyone in your network who has the token can.Offsettings.integrations.mcp.allow_lan
Access tokenClients send it as Authorization: Bearer <token>. Kept in the keyring. Copy token copies it, New token replaces it (old clients stop working).generatedkeyring, not in config.toml
Connect Claude CodeCopy command copies the command that adds Listen to Claude Code. Other clients take the same URL and header.

Advanced

Updates

See Updates.

RowWhat it doesDefaultKey
Check for updatesShows the current version or the result; Check now looks for a new one.
Update availableAppears when a newer version exists; View update opens it.
Check on startLooks for a new version when Listen starts. You decide whether to install it.Onsettings.advanced.update_check_on_start
Release channelStable offers full releases; Beta also offers pre-releases.Stablesettings.advanced.update_channel ("stable", "beta")
Helper programsWindows only. Show and Update manage mpv, yt-dlp and Deno, installed with winget. Update them when YouTube Music songs stop playing.
Release sourceOpen releases opens the public releases page; downloads are checked against their SHA256SUMS. No account needed.

The version you chose to skip and the “remind me later” time are stored in settings.advanced.skipped_version and settings.advanced.update_remind_after.

Listening history

See History, statistics and mixes.

RowWhat it doesDefaultKey
Record listening historySaved only on this computer (song, server, time); never uploaded or shared. Off writes nothing.Onsettings.history.enabled
Don’t record this sessionPauses recording until you close Listen.Offnot saved
Keep history for1 year, 2 years or Unlimited. Older entries are deleted automatically. Unlimited is needed for the year review.Unlimitedsettings.history.retention ("oneyear", "twoyears", "forever")
ExportWrites the history to your Downloads folder as JSON or CSV.
Delete historyDelete all (asks to confirm) removes every entry; statistics and mixes disappear too.

CD ripping

Linux only. See CD ripping.

RowWhat it doesDefaultKey
Auto-rip inserted CDsRips an audio CD as soon as it goes into the drive, also while Listen is in the tray. Always FLAC, secure rip with AccurateRip (whipper), tagged from MusicBrainz.Onsettings.ripping.auto_rip
Music folderAlbums go to Album Artist/Album/NN Title.flac here. Listen never deletes or overwrites anything in it. Save and Choose….Your system Music foldersettings.ripping.destination
Eject when doneEjects the CD after ripping.Onsettings.ripping.eject_when_done
Notification soundPlays a sound with the “Album ripped” notification.Onsettings.ripping.notify_sound
ReplayGain tagsMeasures track and album loudness while tagging.Onsettings.ripping.replay_gain
Scan Navidrome afterwardsAsks Navidrome to look for the new album (needs an admin login; otherwise its file watcher finds it within a minute or two).Onsettings.ripping.scan_navidrome
Version pickerWhen several releases match, the best match is taken after this long, 5 to 120 s.30settings.ripping.picker_timeout_secs
Drive read offsetOffset in samples; empty uses AccurateRip’s drive table. Save, or Verify offset to check it.autosettings.ripping.read_offset
Rip nowShown when a CD is ready. Rip CD rips the disc in the drive.

Import from Feishin

RowWhat it doesDefaultKey
Feishin settings filePath to a Feishin settings export (JSON); press Import. Passwords are ignored. See Importing from Feishin.not saved

Settings backup

See Backup, logs and diagnostics.

RowWhat it doesKey
Export settingsWrites all settings to a JSON file in your Downloads folder. Passwords and tokens are not included.
Import settingsReads a file made by Export settings. Every value is checked; values that do not fit are skipped and listed. Replaces your current settings.

Logging

RowWhat it doesDefaultKey
Log levelHow much listen.log records: Info or Debug. Debug helps when something does not play.Debugsettings.advanced.log_level ("info", "debug")
Export diagnosticsSaves a zip with the logs, your config and the program versions to Downloads. Passwords, cookies, tokens and URL credentials are removed first.

Cache

RowWhat it does
Clear memory cacheSoft clear: forgets covers and data held in memory; they load again as you browse. Files on disk stay.
Cover art cacheDownloaded album and artist images, with the size on disk and a Clear button.
YouTube Music audio cacheSongs kept for gapless play and replays, with size and Clear.
Waveform cacheWaveforms of the player bar slider, with size and Clear.
Clear all cachesRefresh sizes re-measures; Clear all deletes every cache above. Your library, playlists and settings are not touched.

About

The About tab has no options. It shows the version, the license (GNU Affero General Public License v3.0 or later) and a link to the source, followed by credits for the design (Feishin), music sources, online services, and the software, fonts and icons Listen uses.

Keys that have no row

A few keys are stored automatically and are not on the Settings page: settings.settings_tab (the tab you last had open), settings.onboarded (the first-start wizard was finished), settings.window.state (last window size and position), settings.sidebar.width and settings.sidebar.queue_width (dragged panel widths), settings.lists.saved_queries and settings.lists.collections (saved list filters), and the sidebar’s hand-made playlist order.

MCP tools

Every tool of Listen’s MCP server, with its arguments. The server offers 43 tools, which a client reads with tools/list. Arguments marked “required” must be given; the rest are optional.

References

Songs, albums, artists and playlists are named by a ref string:

KindFormat
Songsong:<server>|<id>
Albumalbum:<server>|<id>
Artistartist:<server>|<id>
Playlistplaylist:<server>|<id>

<server> is the id of a music server as list_servers shows it, and <id> is the server’s own id for the item. Do not make refs up: every tool that returns items (search, get_album, get_artist, get_playlist, list_playlists, get_queue, get_now_playing) includes a ref, and Listen remembers the items it has returned since it started. A ref it has not returned gives the error Unknown ref "...". Use a ref returned by search, get_album, get_playlist or get_queue.

Queue entries are not refs; they are named by an integer uid from get_queue. Playlist entries are named by their 0-based position from get_playlist.

Tools that take refs accept songs, albums, artists and playlists unless said otherwise; albums, artists and playlists are expanded to their songs.

Results and errors

A successful call returns the result as pretty-printed JSON text. A tool that fails returns the message as text with isError set to true, for example The queue is empty. or This server can't rename playlists. A call to a tool that does not exist, or without a tool name, is a JSON-RPC error (-32602). A call that takes longer than 60 seconds fails with “timed out”.

Song objects look like this:

FieldMeaning
ref, title, artist, albumIdentity and names
album_ref, artist_refsRefs to open the album or artists
durationSeconds
year, favorite, ratingMetadata

Album, artist and playlist objects have ref, name, favorite or owner/editable, and counts (songs, albums).

Playback

ToolDescriptionArguments
get_now_playingThe playing song, position and duration (seconds), whether it plays, volume, muted, play mode, focus, heart-rate tempo (heart_rate), repeat, speed and the server it comes from.none
playResume playback. Error The queue is empty. if nothing is queued.none
pausePause playback.none
toggle_playPlay or pause.none
nextSkip to the next song.none
previousGo to the previous song (or the start of this one).none
seekJump to a position in the playing song.seconds (number, required): position in seconds
set_volumeSet the volume.volume (integer, required): 0 to 100
set_focusFocus mode on or off: the DJs pick songs with little singing and calm energy, swap sung picks for instrumental versions, and the AI DJ doesn’t talk.on (boolean, required)
set_heart_rateHeart-rate tempo on or off, and/or one reading fed as if it came from the sensor (testing without a strap). Replies with the mode as in get_now_playing’s heart_rate.on (boolean); sample_bpm (number, 30 to 240)
find_instrumentalSearches the instrumental version of a sung queue item right away (no per-fill limit) and, with Focus on, puts it in the item’s place. Replies with the searched uids and queries; the log has one Focus: instrumental of … line per search, found or not. In demo mode the demo library is searched (“Glass Cities” has one).uid (integer): a queue item; without it every upcoming DJ pick
set_play_modeWhat happens when the queue runs out. ai_dj needs a Gemini key.mode (string, required): off, shuffle, auto_dj, ai_dj
set_repeatRepeat nothing, the whole queue or the current song.repeat (string, required): off, all, one
set_speedPlayback speed.speed (number, required): 0.5 to 2.0, 1.0 is normal
sleep_timerStop playback later, or cancel the timer. Give minutes or at.minutes (integer): stop after this many minutes (at most 1440); at (string): end_of_song, end_of_album, cancel, used instead of minutes

Queue

ToolDescriptionArguments
get_queueThe queue. Each entry is a song object plus uid, current (true for the playing one) auto (added by a play mode) and, for a DJ’s pick, why (the reason as a code: {picker, code, args}) and why_text (the reason as shown in the app). Also focus_chip: shown (the Focus chip beside the play-mode button is on screen), on, label.none
play_songsPlay songs, albums, artists or playlists.refs (array of strings, required); how (string): now (replace the queue and play, the default), next (play after the current song), last (add to the end); shuffle (boolean): shuffle them first
add_to_queueAdd items to the end of the queue, or after the current song.refs (array of strings, required); next (boolean): insert after the current song instead
play_queue_entryJump to a queue entry.uid (integer, required)
remove_from_queueRemove entries; the playing one stays. Returns how many were removed.uids (array of integers, required)
move_in_queueMove entries to a position.uids (array of integers, required); position (integer, required): 0-based index they start at
shuffle_queueShuffle the queue; the playing song stays where it is.none
clear_queueDestructive: empties the whole queue and stops playback.none

With play_songs, when the refs mix kinds (for example an album and a playlist), the first kind follows how and the rest are added to the queue.

Library

ToolDescriptionArguments
list_serversThe music servers set up in Listen: id, name, kind, active, connected.none
switch_serverMake another server the active one.server (string, required): id from list_servers
searchSearch songs, albums, artists and playlists on a server.query (string, required); server (string): server id, default the active server; limit (integer): results per kind, default 20, 1 to 100
get_albumAn album with its songs.ref (string, required): album ref
get_artistAn artist with biography, albums and top songs (up to 10).ref (string, required): artist ref
list_playlistsThe playlists on a server.server (string): default the active server
get_playlistA playlist with its songs; each song has a 0-based position.ref (string, required): playlist ref
start_radioPlay a radio of similar songs, seeded with a song or artist.ref (string, required): song or artist ref
get_lyricsThe lyrics of the playing song: provider, synced, and lines with at (seconds), text and translation. {"lyrics": null} if none were found.none

Playlists

ToolDescriptionArguments
create_playlistCreate a playlist on a server, optionally with songs. Only song refs are accepted; add albums later with add_to_playlist. Fails if the server cannot create playlists.name (string, required); server (string): default the active server; refs (array of strings): song refs
add_to_playlistAdd songs, or the songs of albums and artists, to a playlist. All songs must come from the playlist’s server. Returns added_songs.playlist (string, required): playlist ref; refs (array of strings, required)
remove_from_playlistRemove entries by 0-based position (see get_playlist).playlist (string, required); positions (array of integers, required)
rename_playlistRename a playlist.playlist (string, required); name (string, required)
delete_playlistDestructive: deletes a playlist on its server. This cannot be undone. Fails for playlists that are not editable.playlist (string, required)

Servers that cannot do an operation answer with an error such as This server can't add to playlists.

Favourites and ratings

ToolDescriptionArguments
set_favoriteLike or unlike songs, albums or artists (YouTube Music: like or save to library).refs (array of strings, required); favorite (boolean, required): true to like, false to unlike
set_ratingRate songs, albums or artists on servers that support ratings. Playlists cannot be rated.refs (array of strings, required); stars (integer, required): 0 (clear) to 5

AI DJ

ToolDescriptionArguments
get_ai_djThe AI DJ’s setup: enabled, key_stored, persona, voices, models, language, location, pronunciation, details, set size range, talk_every, voice_next (whether the next planned set gets a voiced break; never with Focus on), focus_quiet, voice_gain_db, the active requests (Tell the DJ). Never the key itself.none
list_personasThe AI DJ’s personas with id, name, description and voices.none
set_ai_djChange the AI DJ. Only the given fields change; returns the new setup.see below
tell_djTell the AI DJ what you want: a new request replans the queued, not yet started part of the set at once (the playing song goes on); the same request again changes nothing. Requests stay until removed. Returns the AI DJ setup with requests and changed.request (string): calmer, more_energy, more_new, only_favourites, focus, korean_only, no_ballads or free text; remove (string): an active request; clear (boolean): remove all
set_gemini_keyStore a Gemini API key for the AI DJ in the system keyring. An empty string removes it. The key is never returned by any tool.key (string, required): the key from Google AI Studio

set_ai_dj arguments (all optional):

ArgumentTypeMeaning
enabledbooleanSwitch the AI DJ on or off. Switching on needs a Gemini key (set_gemini_key).
personastringPersona id from list_personas.
tts_modelstringVoice model: gemini-3.8-flash-lite-tts or gemini-3.8-flash-tts.
languagestringLanguage code the hosts speak (en, de, fr, …); empty means the app’s language.
locationstringWhere the show airs; empty means no home town.
pronunciationstringHow the voice says the place name.
detailsstringFree text for the hosts: names, likes, topics to avoid.
set_maxintegerSongs per set, 2 to 8.
talk_everyintegerTalk after every n-th set, 1 to 5.
voice_gain_dbnumberVoice loudness relative to the music, -12 to 12 dB.

Remember that the AI DJ sends song titles, artists, the DJ’s lines and your “Details” text to Google; see AI DJ.

Settings and analysis

ToolDescriptionArguments
get_settingsAll of Listen’s settings as JSON, with passwords and keys left out.none
set_settingsChange settings with a partial object that is merged key by key, for example {"playback":{"gapless":"yes"}}. Invalid values are refused and listed; the rest is applied. Returns applied and refused.settings (object, required): the same shape get_settings returns
get_analysis_statusHow far the song analysis for DJ transitions is: whether analysis and DJ transitions are on, songs analysed, songs waiting, the current song and any error.none

set_settings also applies changes that need work, such as audio settings and the remote and MCP servers.

See Settings for what each setting does.

Command line

Listen is a normal desktop program, so you rarely need the command line. This page lists every option of the listen command, the self-check commands that help with problems, and the environment variables Listen reads. On Windows, use listen.exe from a terminal; its output appears in the terminal you started it from.

listen [OPTIONS]

Starting the app

OptionWhat it does
--demoUses the built-in demo library and generated audio. No server needed and nothing is saved. A good way to look around first.
--queueOpens the queue sidebar at start (with --demo).
--videoStarts with the song/video switch on (with --demo).
--theme <ID>Forces a theme by its id for this run, for example tokyoNight or defaultLight.
--size <WxH>Initial window size in pixels, for example --size 1280x800. The default is 1600x950.
--route <PAGE>Opens on home, albums, tracks or settings. If Listen is already running, the running window is brought forward and shown that page.
--login <URL> <USER>Signs in to a server for this run only. The password is read from the environment variable LISTEN_PASSWORD. Nothing is saved.
--autoplayStarts playing the first album on the home page (with --login).
--ephemeralDoes not read or write settings or credentials. Meant for tests and demos.
--onboardingShows the first-start wizard again (combine with --ephemeral to see it without changing your settings).
--screenshot <PATH>Saves a PNG of the window after start-up and exits.
--screenshot-delay <MS>Waits this long before the screenshot. The default is 2500.
-h, --helpPrints the usage text and exits.
-V, --versionPrints the version and exits.

An unknown option prints an error with the usage text and exits with status 2.

Listen allows one running copy per user. Starting it a second time brings the first window forward and exits (it prints “Listen is already running; brought it forward.” and returns 0), except with --demo, --ephemeral, --screenshot and --login, which start their own copy.

Check commands

These commands do their job in the terminal and exit; they never open the window. They must be the first argument. They read your normal configuration and sign-ins, print what they find with a check mark or cross for each step, and exit with 0 when everything is fine and 1 otherwise. Use RUST_LOG=debug to see more detail.

CommandWhat it does
listen --check-youtube-musicSigns in to YouTube Music the way the app does (with your browser’s session) and prints what Listen sees of your library: counts and page titles only, never cookies. Also checks that a stream can be resolved with yt-dlp.
listen --check-ai-dj [--no-voice] [--rounds N] [--no-judge] [--dump-prompt] [--request R] [--offline]Runs AI DJ rounds (2 by default) against Gemini with a sample song pool that carries play counts, “new to you” tags and tempo/key/energy, and saves the first two spoken breaks as WAV files. A second Gemini call grades every break (no invented facts, persona, language, no repeats, no talk about the mixing, a new-to-you song gets introduced); the command fails if fewer than 80 % of the breaks pass or fewer than 80 % of the sets with a new song introduce one. --no-voice skips the speech, --no-judge the grading, --dump-prompt prints each prompt. --request (repeatable: calmer, more_energy, more_new, only_favourites, focus, korean_only, no_ballads or free text) tells the DJ a request before round 2, as Tell the DJ does; with Calmer or More energy the command fails unless the next 5 songs have less (more) energy on average than the first set. At the end it prints the tokens per plan. --offline needs no key and costs nothing: a stand-in planner picks against the request (the most energetic songs left for Calmer, the calmest for More energy), so only Listen’s own song filter can keep the request; no speech, no grading. Otherwise it needs a Gemini key (saved in Settings or in LISTEN_GEMINI_API_KEY) and uses your Gemini quota: one text request per round, one more for the grade, and up to two speech requests.
listen --song-card <TITLE> <ARTIST> [--album A] [--year Y] [--lang de|en]Builds the full-screen About card for a song and prints it as JSON with a summary line (facts, credits, whether it would be shown). Fails when a fact has no source link. Needs a Gemini key and costs up to three Gemini requests; nothing is cached.
listen --known-words <TITLE> <ARTIST> [--lrc FILE] [--hub URL]Prints a song’s Korean words with their Lute status and the share of known words as JSON, the way the lyrics’ WORDS mode colours them and the Learnable songs mix counts them. Lyrics come from lrclib (or an LRC file); the hub from --hub or the lyrics settings. Only reads from the hub.
listen --weekly-stats [--history PATH] [--now UNIX]Prints the numbers of Statistics → Last 4 weeks as JSON: this week and last week (plays, listening time, skips, different songs and artists), the 4 weeks’ totals and top lists, new artists this week and the songs skipped most. --history reads another history.jsonl (default: this computer’s), --now sets the moment the rolling windows end.
listen --check-cdChecks CD ripping without ripping: tools, drive and read offset, the disc’s table of contents and MusicBrainz match, the music folder and Navidrome. See CD ripping.
listen --check-analysis [N | FILE-OR-URL | ytm:ID | ytm [N]]Analyses N random Navidrome songs (default 20) and compares the tempo with BPM tags, or prints the full analysis of one file, URL or YouTube Music song.
listen --analyze-library [--jobs N]Analyses every not-yet-analysed Navidrome song, N at a time (default 3), into the analysis folder, outside the app. It writes under its own name, so a running Listen does not collide with it.
listen --check-mix A B [--render OUT.wav] [--lyrics-a A.lrc] [--lyrics-b B.lrc] [--levels OUT.jsonl]Plans the DJ transition from song A into song B as the player would and optionally renders a preview file. A song is a Navidrome song id, ytm:<videoId>, a local file or a URL. Synced lyrics given as LRC files are used like fetched ones (where the singing is, line ends, chorus). Prints the plans the check rejected and the chosen plan’s check; with --render it also prints the rendered preview’s loudness hole and bump. --levels writes each song’s modelled and measured local loudness every 0.5 s (also through the bass swap’s shelf) with its bar curves.
listen --check-ytm-session [--write]For developers. Tests the write functions of the YouTube Music session (like and unlike, a throwaway playlist) and undoes them. Without --write it only prints its plan. It acts on your real account, so only use it if you know why.

listen --analysis-worker is used internally by Listen to analyse songs in a separate process. You do not run it yourself.

Environment variables

Set these in the terminal before the command (LISTEN_LANG=de listen) or, for a permanent effect, in your desktop session or the launcher.

Useful for everyone

VariableEffect
LISTEN_LANGOverrides the language for this run. Use a code from the language list (en, de, fr, es, zh-Hans, …) or a locale name such as de_DE.UTF-8. See Languages.
LISTEN_GEMINI_API_KEYGemini API key for the AI DJ. When set, it is used instead of the key saved in the keyring. See Creating a Gemini API key.
LISTEN_YTDLPFull path of the yt-dlp program to use for YouTube Music. Without it Listen runs yt-dlp from the PATH (on Windows also next to listen.exe and in %LOCALAPPDATA%\Listen\bin).
LISTEN_MPVFull path of the mpv program. Takes precedence over Settings → Playback → mpv → Executable path.
LISTEN_MPV_ARGSExtra mpv options for this run, separated by spaces, added to the Extra parameters from the settings. Example: LISTEN_MPV_ARGS="--ao=null" for a silent run.
LISTEN_PASSWORDThe password for --login.
RUST_LOGHow much Listen prints to the terminal, in the usual Rust syntax, for example RUST_LOG=debug or RUST_LOG=listen=trace,warn. The default is listen=info,listen_core=info,warn. It does not change listen.log; that is set by Log level in the settings.

Display and graphics

VariableEffect
WINIT_UNIX_BACKENDSet to x11 on a Wayland session to run Listen through X11 instead.
LISTEN_MILKDROP_EGLForces how the Milkdrop visualizer creates its graphics context: device (a GPU device), surfaceless (Mesa) or default. By default Listen tries them in that order. Useful when Milkdrop shows nothing.
LISTEN_VIZ_DEBUGSet to 1 to log visualizer frames and audio capture start and stop once a second.

Analysis

VariableEffect
RTEN_NUM_THREADSNumber of threads for the beat-detection model. If you set it, it wins over the threads setting; otherwise Listen sets it from the setting.
LISTEN_ANALYSISAny value turns song analysis on in an --ephemeral run (it is off there by default).

Folders

On Linux the standard XDG variables XDG_CONFIG_HOME, XDG_DATA_HOME, XDG_CACHE_HOME and XDG_RUNTIME_DIR decide where Listen keeps its files; see Files and folders. On Windows APPDATA and LOCALAPPDATA do.

Testing and development

You will not need these in normal use.

VariableEffect
LISTEN_AI_DJ_PERSONAPersona id for --check-ai-dj.
LISTEN_AI_DJ_JUDGE_MODELText model that grades the breaks in --check-ai-dj (default: the AI DJ’s text model).
LISTEN_AI_DJ_MODESForces the order of AI DJ break types, for example outro,intro,across,between.
LISTEN_AUTOPLAY_ALBUMWith --autoplay, plays the first search result for this album name instead of the first home album.
LISTEN_CHECK_STREAMS, LISTEN_CHECK_ALL, LISTEN_CHECK_SHAPEExtend --check-youtube-music: open N random tracks in a silent mpv, open every playlist and album instead of a few, and print the page structure of the first album that fails to open.
LISTEN_STARTUP_DELAY_MSWaits up to 5000 ms before starting. Listen sets it itself when it restarts on Windows.
LISTEN_I18N_COLLECTWrites the interface texts that are shown to the given file, for translators. See Translations.
LISTEN_DEMO_VIDEO_KBPS, LISTEN_DEMO_VIDEO_FIRST_BYTE_MSSpeed of the demo video stream.

Files and folders

This page lists where Listen keeps its files on Linux and Windows: settings, history, caches, logs, your own themes and presets, and the program’s helper files. Listen stores everything in your user account; it never writes outside your home or profile except to the music folder you choose for CD ripping.

The three base folders

Listen uses the standard per-user folders of your system, under the application name Listen.

FolderLinuxWindows
Config~/.config/listen%APPDATA%\Listen\config
Data~/.local/share/listen%APPDATA%\Listen\data
Cache~/.cache/listen%LOCALAPPDATA%\Listen\cache

On Linux the folders follow XDG_CONFIG_HOME, XDG_DATA_HOME and XDG_CACHE_HOME when you have set them. On Windows %APPDATA% is usually C:\Users\<you>\AppData\Roaming and %LOCALAPPDATA% is C:\Users\<you>\AppData\Local.

Rule of thumb: config is what you would want to keep, data is what Listen has learnt or saved for you, and cache can be deleted at any time.

Config folder

PathContent
config.tomlAll settings, your list of servers (name, kind, address, user name), per-server options and the setting for password storage. Contains no passwords. Written atomically, so a crash cannot leave it half-written.
credentials.tomlPasswords, tokens and keys, only when the system keyring is not used or not available (“File only” or no keyring). On Linux readable by your user only (permissions 0600). Delete a server in Listen to remove its entry.
themes/Your own themes. See Custom themes.

If config.toml cannot be read because it is damaged, Listen starts with default settings and logs a warning. Keep a copy, or use Export settings (see Backup, logs and diagnostics).

Data folder

PathContent
logs/listen.log, mpv.log (and the previous run as .log.1) and rip-*.log from CD rips.
history.jsonlYour listening history, one line per play. Local only.
flow-weights.jsonThe DJ flow weights learnt from your early skips (Auto-DJ setting Learn from my skips); rebuilt from the history (or taken from another device through listen-server), safe to delete.
queue.jsonThe play queue, restored at the next start.
analysis/Song analysis results (tempo, key, sections), unless you set another Analysis folder in the settings.
offline/Songs you downloaded for offline playback from your own servers, with an index. The folder is private to your user. See Downloads.
milkdrop/presets/Milkdrop presets (.milk files) when you have not chosen another preset folder.
lyrics_overrides.jsonWhich lyrics match you picked for songs.
ai-dj-quota.jsonThe count of AI DJ spoken breaks voiced today, and whether Google reported the speech quota as used up.
rips.jsonDiscs you have ripped, including those listed under Rips to fix.
models/The optional singing-voice detector (djustify-svdnet.pt, 2 MB) when you downloaded it in the analysis settings.

Cache folder

Everything here is created again when needed.

PathContentCleared by
covers/Downloaded album and artist imagesSettings → Advanced → Cache → Cover art cache
ytm-audio/Audio kept for YouTube Music songs so they can play gapless and replay quickly; limited to about 500 MBYouTube Music audio cache
waveforms/Waveforms for the player bar sliderWaveform cache
models/The beat-detection model for song analysis (about 11 MB), downloaded oncenot listed; delete the folder to fetch it again
dj/Clips of the AI DJ’s spoken breaksnot listed
updates/Downloaded update filesnot listed
rips/Work files of CD rips (Linux)not listed

Other places

PathUsed for
~/Downloads (your system’s Downloads folder)Where exports go: settings (listen-settings-<date>.json), diagnostics (listen-diagnostics-<date>.zip) and history (JSON or CSV).
Your music folder (default ~/Music, set in Settings → Advanced → CD ripping)Ripped albums as Album Artist/Album/NN Title.flac, with a hidden .listen-incoming folder while copying.
~/.config/whipper/whipper.confwhipper’s own configuration, including the drive offset found by Verify offset. Linux only.
$XDG_RUNTIME_DIR/io.github.leks2205.Listen.sockLocal socket through which a second start reaches the running Listen (Linux). The file io.github.leks2205.Listen.lock plays this role on Windows. Without XDG_RUNTIME_DIR a private folder listen-<user> in the temp folder is used.
$XDG_RUNTIME_DIRAlso holds the private socket of the audio player (mpv).
%LOCALAPPDATA%\Listen\binHelper programs (mpv, yt-dlp, Deno) when they are installed there. Listen looks for helpers next to listen.exe, then on the PATH, then here and in winget’s folders.
%LOCALAPPDATA%\Programs\ListenThe Windows installation (installer without administrator rights).
Your KDE colour scheme and theme-switcher filesRead, never written, when Follow desktop theme is on (Linux).

Backing up and moving

  • To move your setup to another computer, use Export settings and Import settings, then add your servers again. See Backup, logs and diagnostics.
  • To back up everything Listen knows, copy the config and data folders while Listen is closed. Passwords stored in the keyring are not in these folders; they stay with your user account’s keyring.
  • To start fresh, close Listen and rename the three folders. Listen creates new ones at the next start.
  • To remove all traces, delete the three folders and, if used, the entries for io.github.leks2205.Listen in your keyring.

Note: The application ID io.github.leks2205.Listen is also the name of the desktop file, the icon and the Wayland application ID.

Building from source

This page covers the toolchain, the system packages Listen needs, how to run it (including the demo library), how to cross-compile the Windows build from Linux, and the basic rules for contributions.

Toolchain

  • A recent stable Rust toolchain installed with rustup. The workspace uses the 2024 edition and Cargo resolver 3, so an old distribution Rust will not do.
  • A C compiler and pkg-config.
  • mpv, which Listen drives for all playback. It is needed at run time and by some tests.
  • Optional at run time: yt-dlp and Node.js or Deno (YouTube Music), whipper, flac and cdrdao (CD ripping), PipeWire (the visualizer’s audio capture on Linux).

Get the code:

git clone https://github.com/leks2205/Listen.git
cd Listen

Linux packages

The window, the GPU and the keyboard libraries are loaded at run time with dlopen, so a build needs only a few development headers. The list below matches what the CI workflow installs.

Debian and Ubuntu

sudo apt-get install --no-install-recommends build-essential pkg-config \
    libxkbcommon-dev libwayland-dev libudev-dev mpv

Fedora

sudo dnf install gcc pkgconf-pkg-config libxkbcommon-devel wayland-devel \
    systemd-devel mpv

At run time the RPM (packaging/listen.spec) requires these libraries, which are good to have on any distribution: libglvnd-egl, libwayland-client, libwayland-egl, libxkbcommon, libxkbcommon-x11, libX11, libX11-xcb, libxcb, libXcursor, libXi, libXrandr. Install Mesa and Vulkan drivers (mesa-dri-drivers, mesa-vulkan-drivers, vulkan-loader on Fedora) so the GPU renderer starts. A system font with Korean glyphs (Noto Sans CJK KR) is used for Korean titles and lyrics.

Running

cargo run --release -p listen                  # normal start
cargo run --release -p listen -- --demo        # built-in demo library, no server needed

Everything after -- goes to Listen. See Command line for all options.

Demo mode

--demo starts with a generated library of albums, artists, playlists and radio stations. No server is contacted. Demo songs play generated audio through mpv. Useful companions:

OptionEffect
--ephemeralNever write settings or credentials. Use it for experiments and screenshots.
--queueOpen the queue sidebar on start.
--videoStart with the song/video switch on.
--theme <ID>Force a theme, for example tokyoNight or defaultLight.
--route <PAGE>Start on home, albums, tracks or settings.
--onboardingShow the first-start wizard even in demo or ephemeral runs.
--size <WxH>Initial window size. The default is 1600x950.

Environment variables for development: LISTEN_MPV_ARGS adds mpv options (for example --ao=null to stay silent), LISTEN_MPV and LISTEN_YTDLP point to a specific binary, and LISTEN_LANG forces the interface language.

Logs

Debug output uses tracing. Set RUST_LOG, for example RUST_LOG=listen=debug, to see more. The log folder is printed at start-up; see Backup, logs and diagnostics.

Release profile

Cargo.toml defines the release profile: thin LTO, four codegen units and stripped symbols. The dev profile keeps line tables for the workspace crates and compiles dependencies with opt-level = 1, which keeps debug builds responsive. Audio analysis is slow in an unoptimised build, so use --release when you test the DJ features.

Windows cross-compile with MinGW

Windows builds are produced on Linux. .cargo/config.toml already sets the linker (x86_64-w64-mingw32-gcc) and the CC and AR variables for the target.

  1. Install the MinGW toolchain: sudo dnf install mingw64-gcc on Fedora, or sudo apt-get install gcc-mingw-w64-x86-64 on Debian and Ubuntu.
  2. Add the Rust target: rustup target add x86_64-pc-windows-gnu.
  3. Build:
cargo build --release --target x86_64-pc-windows-gnu -p listen

The result is target/x86_64-pc-windows-gnu/release/listen.exe. To build the installer, see Packaging and releases. On Windows the app finds mpv, yt-dlp and Deno through its helper-program settings; the installer fetches them with winget on first start.

Contributing

Bug reports and pull requests are welcome. Before you open a pull request, run the same checks as CI:

cargo fmt --all --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace

CI runs the first two plus cargo test --workspace --lib on Ubuntu for every push to main and every pull request. Tests that need mpv or a live server skip themselves when it is missing; see Tests. Keep a pull request focused on one change, and add or update a test when you fix a bug. New user-visible text must go through the translation system; see Translations.

Listen is licensed under AGPL-3.0-or-later. By contributing you agree that your change is released under that license.

Architecture

Listen is a Cargo workspace: one application crate (app, binary name listen) and a set of library crates under crates/. This page explains what each part does and how data flows through the app.

Workspace crates

CrateWhat it does
listen-coreData model (songs, albums, artists, playlists), the play queue, history, the settings structs and their defaults, the Feishin settings importer, themes, and the shared analysis types. No UI and no network code.
listen-sourceThe MusicSource trait that every backend implements, a Capabilities bit set (folders, ratings, radio, playlist editing, lyrics and so on), query and sort types, client-side sorting and filtering, and the parser for Navidrome smart playlists (nsp).
listen-subsonicNavidrome and OpenSubsonic backend.
listen-jellyfinJellyfin backend, including Quick Connect and server discovery.
listen-ytmusicYouTube Music backend. See YouTube Music internals.
listen-localLocal folders: scanner and tag reader.
listen-playerThe mpv wrapper: starts mpv with a JSON IPC socket, keeps the two-slot (current and next) gapless model, reports events and audio timestamps.
listen-analysisSong analysis: decoding through mpv, beat and downbeat tracking, key, structure, timbre, loudness, the waveform, the shard-based result store and the analysis worker protocol.
listen-mixDJ transition logic without DSP or mpv: scoring how well two songs follow each other, ordering DJ picks, and planning where and how to mix.
listen-djThe AI DJ: prompts, personas, the Gemini text and speech client, request quota.
listen-lyricsLyrics providers, LRC parsing, ranking, translation and romanisation helpers.
listen-visualizerAudio capture and spectrum analysis for the visualizer.
listen-dlnaUPnP/DLNA casting: discovery, SOAP control and a streaming proxy.
listen-offlineDownloaded songs.
listen-ripCD ripping pipeline (whipper, FLAC, MusicBrainz tags).

The app crate

app/src/main.rs only calls into app/src/lib.rs, which parses the command line (Args) and starts the iced application. Most of the code is under app/src/app/, with one module per feature area:

AreaModules
Playbacktransport, queue_ui, play_mode, fade, audio, sleep_timer, decks, mix/, dj, dj_mix, video/
Library pageshome, album_page, artist_page, list, list_query, search, playlists/, smart_playlist, radio, item/
Integrationsintegrations (remote control, Discord, MPRIS, tray), mcp, dlna, updater
Settingssettings_shell, settings_msg, advanced, appearance
Miscanalysis, history, offline, rip, milkdrop, viz, onboarding, palette, overlay, menu/

The user interface is in app/src/ui/: one module per page or widget group (player bar, queue, settings tabs, context menu and so on). app/src/i18n.rs holds the translation tables, app/src/mpris.rs, smtc.rs, tray.rs, discord.rs and global_shortcuts.rs hold the platform integrations, app/src/mcp/ and app/src/remote/ hold the two network servers, and app/src/demo.rs builds the demo library.

The Elm architecture in iced

Listen follows iced’s Elm-style loop. The central type is Listen in app/src/app.rs, which holds all state. Four functions on it drive the app:

  • update(&mut self, Message) -> Task<Message> changes the state in response to a message and may return tasks (asynchronous work) whose results come back as new messages. It dispatches to update_message, which hands each message group to the matching app/*.rs module.
  • view(&self) -> Element<Message> builds the whole widget tree from the state. It never changes anything.
  • subscription(&self) -> Subscription<Message> lists the event streams the app listens to right now: window and keyboard events, timers, mpv events, and the background streams described below. The list depends on the state, so a stream is only active when its setting is on.
  • theme(&self) and title(&self) give the current theme and window title.

Message is one large enum whose variants are grouped by feature (for example the Mcp(McpMsg) variant for everything the MCP server sends).

 user input ---------------> view() --Message--+
 window / keyboard / timers -> subscription() --+
 mpv events (listen-player) -> subscription() --+--> update() --> state (Listen)
 analysis worker ----------> subscription() ----+        |            |
 MCP server calls ---------> subscription() ----+        |            v
 remote control commands --> subscription() ----+        |         view()
 finished Tasks ------------------------------------------+
                                                         v
                                   Task: network requests, mpv commands, files

Music sources

All backends implement the MusicSource trait from listen-source. The app holds one Arc<dyn MusicSource> per configured server (SourceHandle) and calls the same methods for every kind of source: listing and searching albums, artists, songs and genres, playlists, lyrics, similar songs, radio, scrobbling and resolving a stream URL. Features a backend lacks are declared through Capabilities; the UI hides the matching controls. Adding a source means implementing the trait in a new crate and wiring it up where the app connects to servers (see app/src/app/servers.rs).

Playback and the two mpv decks

listen-player starts an mpv process per player and talks to it over its JSON IPC. The queue lives in the app, not in mpv. mpv holds two entries, the current song and the next one, and moves to the next gaplessly; the app then drops the finished entry and appends the following song.

app/src/app/decks.rs wraps two such players. The active deck plays the current queue song. The idle deck is empty, or it carries the incoming song during a DJ transition. Without transitions only deck 0 runs. During a transition app/src/app/mix/ preloads the incoming song paused on the idle deck, starts it at the planned moment, phase-locks it to the outgoing deck by nudging its speed, applies the planned volume and EQ envelopes, and makes it the active deck halfway through. Anything unexpected cancels back to gapless playback. See DJ transitions internals.

Analysis worker

Analysis runs in a separate short-lived helper process, started as listen --analysis-worker. Decoding and the beat model use a lot of memory that the allocator does not return, so the helper exits when idle and is replaced when it grows too large. The protocol is one JSON line per request on stdin and one per answer on stdout (crates/listen-analysis/src/worker.rs).

On the app side, app/src/app/analysis.rs owns the job queue (the play queue first, then the AI DJ’s candidate pool, then the library crawl), starts the helper, writes results to the shared store and exposes lookups for the mixer and the Auto-DJ. Results reach the update loop as messages from a subscription.

MCP and remote servers

Both servers run on the tokio runtime, in the same process, and never touch the state directly.

  • app/src/mcp/ is the MCP server (Streamable HTTP, bearer token). It answers initialize, ping and tools/list itself. A tools/call becomes a Call with a one-shot reply channel and is sent through a channel to the app. app/src/app/mcp.rs turns that channel into a subscription, executes the tool inside update (so it sees the same state as the UI) and answers through the reply channel. Tools that ask a server run as tasks and answer when they finish.
  • app/src/remote/ is the remote control server: HTTP plus WebSocket on one port, an embedded phone page and Feishin’s message format. The app publishes a snapshot of the player (Shared) for clients to read; commands from clients arrive through a channel that app/src/app/integrations.rs exposes as a subscription.

Because every outside command goes through a Message, there is one place where state changes. This also makes the servers testable: app/tests/mcp.rs and app/tests/remote.rs drive the real update loop without a window.

Persistence

Settings and server lists are TOML files handled by listen-core::config; credentials go to the system keyring, with a private credentials.toml as the fallback. Analysis results live in a shard store that several computers can share. See Files and folders.

Translations

Listen’s interface is translated into 16 languages besides English. This page explains how the translation tables work, how to improve one, and how to add a language.

How lookup works

Listen uses a gettext-style scheme: the English text is the key. Code writes the English string and wraps it with tr() (or trf() for texts with values); the active table maps the English text to the translation. If the table has no entry, the English text is shown, so a missing translation never breaks the interface. English itself has no table.

FunctionUse
tr(s)Look up a fixed text.
tr_cow(s)The same for a Cow<str>.
trf(pattern, args)Look up a pattern with {} holes and fill the holes with args in order.

Because the English text is the key, changing an English string in the code also changes its key. After editing a string, update every table that has the old text, or the translations stop matching.

Files

PathContent
app/i18n/<code>.jsonThe merged table for one language: a flat JSON object, English text to translation. This is what the app embeds with include_str!.
app/i18n/listen/<code>.jsonStrings that exist only in Listen (not in Feishin). These are the files to edit by hand.
tools/gen_i18n.pyBuilds the merged tables.
app/src/i18n.rsThe LANGUAGES list, the lookup code and the locale detection.

The merged files are generated. Do not edit app/i18n/<code>.json directly; your change would be overwritten the next time the script runs. Put Listen-only strings into app/i18n/listen/<code>.json.

Generating the tables

Many of Listen’s labels are the same as Feishin’s, so their translations are reused. tools/gen_i18n.py takes the folder with Feishin’s locale files:

python3 tools/gen_i18n.py /path/to/feishin/src/i18n/locales

For each language the script:

  1. Collects every string literal in the Rust sources of app/ and crates/ (test files excluded) that looks like UI text.
  2. Matches each literal against Feishin’s English strings, ignoring case and whitespace, and takes Feishin’s translation for the matching key. Feishin’s {{name}} holes become {}.
  3. Adds the entries of app/i18n/listen/<code>.json. These win over Feishin’s.
  4. Writes app/i18n/<code>.json, sorted by key.

It also writes app/i18n/.unmatched.json, the literals that matched nothing in Feishin. That list shows what still needs a Listen-only translation.

Finding what is missing

Run the app in a language and let it record the texts without a translation:

LISTEN_LANG=de LISTEN_I18N_COLLECT=/tmp/missing.txt cargo run --release -p listen -- --demo

LISTEN_LANG forces the language. LISTEN_I18N_COLLECT appends every untranslated text to the file, once each, as JSON strings. Click through the pages you want to check, then add those texts to app/i18n/listen/<code>.json and run gen_i18n.py again.

Placeholder rules

Texts that are built from a pattern use {} for each value, for example "Added {} songs".

  • The translation must contain no more {} than the English text, and should contain the same number. A translation with more holes is dropped by the generator and ignored by the app.
  • Holes are filled in order. A translation may leave out trailing holes, but it cannot reorder them.
  • Keep the {} exactly as written, with no spaces inside.
  • A very short pattern such as "{} songs" only matches when the filled-in value is a number, so it does not catch user text like “Love songs”. Write short patterns with this in mind.

Adding a language

  1. Add the language to LANGUAGES in app/src/i18n.rs. The first item is the code, the second the language’s own name:

    #![allow(unused)]
    fn main() {
    ("sv", "Svenska"),
    }
  2. Add the code to english_name() in the same file. The AI DJ uses it to name the language in its prompt.

  3. Add a line to source() that embeds the table: "sv" => Some(include_str!("../i18n/sv.json")),.

  4. Add the code to the langs set in tools/gen_i18n.py.

  5. Create app/i18n/listen/sv.json with at least {}, then fill it with translations, and run tools/gen_i18n.py against Feishin’s locale files. If Feishin has no locale of that code, the table is built from your Listen-only file alone.

  6. Update the language count in the every_language_has_a_table_that_parses test in app/src/i18n.rs. That test also requires each table to hold more than 1000 entries, so a new language needs a substantial first translation.

  7. Run cargo test -p listen --test i18n and cargo test -p listen --lib i18n, and look at the result with LISTEN_LANG=sv cargo run --release -p listen -- --demo.

Right-to-left languages (Arabic and Urdu are present) are drawn right to left automatically by the text layout; check the layout of the player bar and the settings pages when you add one.

The language picker in Settings -> General -> Application -> Language lists LANGUAGES plus an entry that follows the system language. The system language comes from LC_ALL, LC_MESSAGES or LANG; pt_BR and pt_PT map to pt, any zh_* maps to zh-Hans, and unknown languages fall back to English.

License note

The files app/i18n/<code>.json contain translations taken from Feishin, which is licensed under GPL-3.0. They stay under GPL-3.0 and are combined with Listen under section 13 of the GPLv3 and the AGPLv3; see NOTICE.md. The Listen-only files in app/i18n/listen/ are AGPL-3.0-or-later. If you contribute a translation, you agree to this split. Do not copy translations from sources with an incompatible license.

Tests

This page describes the test suite, the tests that need extra programs or a live service, the end-to-end DJ test, and how to produce screenshots.

Running the tests

cargo test --workspace            # everything
cargo test --workspace --lib      # unit tests only (what CI runs)
cargo test -p listen --test mcp   # one integration test file of the app
cargo test -p listen-mix          # one crate

Unit tests live next to the code in #[cfg(test)] modules. The app/tests/ folder holds integration tests that boot the real Listen state with the demo library and ephemeral set (nothing is written to disk) and drive it through update(Message). They cover the queue, play modes, Auto-DJ, playlists, settings, hotkeys, the MCP and remote servers, the updater, layouts at different window sizes, and more. Crates have their own tests/ folders, for example the fake-server tests in listen-subsonic, listen-dlna and listen-jellyfin.

CI (.github/workflows/ci.yml) runs cargo fmt --all --check, cargo clippy --workspace --all-targets -- -D warnings and cargo test --workspace --lib.

Snapshot tests

app/tests/snapshots.rs renders pages headlessly with iced_test and writes PNG files to target/snapshots/ for visual review. The test also compares against a previous image where one exists. Run it with output visible:

cargo test -p listen --test snapshots -- --nocapture

Open the PNG files after a UI change to see what the pages look like. app/tests/live_pages.rs does the same with data from a real server (see below).

Tests that need mpv

crates/listen-player/tests/mpv_playback.rs and deck.rs drive a real mpv with --ao=null, so they make no sound. They look for mpv on PATH and skip themselves when it is missing. Set LISTEN_MPV=/path/to/mpv to use a specific binary. LISTEN_MPV_ARGS="--ao=null" also silences mpv for the app’s own tests.

Live tests

Live tests talk to a real server or service. They skip silently unless their environment variables are set, so cargo test --workspace stays offline.

VariablesTestNeeds
LISTEN_ND_URL, LISTEN_ND_USER, LISTEN_ND_PASSlisten-subsonic/tests/live_navidrome.rs, app/tests/live_pages.rsA Navidrome or OpenSubsonic server with at least one album
LISTEN_JF_URL, LISTEN_JF_USER, LISTEN_JF_PASSlisten-jellyfin/tests/live_jellyfin.rsA Jellyfin server with at least one album
LISTEN_LYRICS_LIVE=1listen-lyrics/tests/live_lrclib.rsInternet access (looks up a well-known song on lrclib.net)
LISTEN_VIZ_LIVE=1listen-visualizer/tests/live_capture.rsLinux with PipeWire and mpv
LISTEN_YTM_LIVE=1listen-ytmusic/tests/live_ytdlp.rsInternet, yt-dlp and a JavaScript runtime. LISTEN_YTM_COOKIE can supply a cookie header; the default is a guest cookie.
LISTEN_TEST_URL=<stream URL>listen-ytmusic/src/audio.rs, run with -- --ignored download_urlA stream URL you resolved yourself

Example:

LISTEN_ND_URL=https://music.example.com LISTEN_ND_USER=alex LISTEN_ND_PASS=secret \
    cargo test -p listen-subsonic --test live_navidrome

Never commit credentials. Use a test account on a test server.

Other development variables: LISTEN_ANALYSIS=1 turns song analysis on in an ephemeral session, LISTEN_AUTOPLAY_ALBUM=<title> makes --autoplay start that album, LISTEN_RIP_KEEP=<dir> keeps the album produced by the ripping pipeline test, and LISTEN_VIZ_DEBUG=1 prints visualizer diagnostics.

The DJ end-to-end test

tools/dj-e2e.sh [minutes] tests DJ transitions in the real app. It generates synthetic songs with known beat grids, starts a local Navidrome on a fresh database, creates a private PipeWire graph with a null sink, runs Listen headless under Xvfb with the Auto-DJ and mixing on, and then summarises the mixer log and a recording of the sink (silent gaps, two decks at full level, doubled onsets). Everything is isolated in a work folder, and no real configuration or credentials are touched.

Needs: navidrome (path in NAVIDROME), PipeWire with pw-record, xvfb-run, dbus-run-session and a release build (LISTEN_BIN, built if missing). Useful variables:

VariableEffect
DJ_E2E_DIRWork folder (default /tmp/dj-e2e).
DJ_E2E_KEEP=1Keep the run folder with logs and the recording.
DJ_E2E_RECORD=0Do not record the sink.
DJ_E2E_ACTIONS=1Press next, pause, seek and next-while-preloading over MPRIS during the blends to test the cancel paths.
DJ_E2E_MODELSCache folder for the beat model between runs.

Screenshots

Demo mode gives repeatable content for screenshots:

tools/screenshot.sh out.png 1600x950 --demo --route albums
tools/screenshot.sh onboarding.png 1000x700 --ephemeral --onboarding

tools/screenshot.sh OUT.png WxH [listen args] runs Listen on a virtual X screen (xvfb-run), because some compositors ignore requested window sizes, and passes --screenshot and --size to the app. It uses target/release/listen unless LISTEN_BIN is set. Useful options to combine: --theme <ID>, --queue, --video, --screenshot-delay <ms> for pages that need time to load, and LISTEN_LANG=<code> for translated screenshots. --onboarding shows the first-start wizard even in a demo or ephemeral run.

Packaging and releases

This page describes how release artifacts are built: the RPM and tarball, the Windows installer, the third-party license page, and the GitHub release that the in-app updater reads.

Version

The version is the single version line under [workspace.package] in the root Cargo.toml. All crates inherit it. The packaging scripts read it from there, listen --version prints it, and the updater compares it with the newest release tag. To release, raise the number, build, and tag the commit vX.Y.Z. A tag containing a hyphen, such as v0.35.0-beta.1, is a pre-release.

RPM and tarball

Build the release binary first, then run the script from anywhere inside the repository:

cargo build --release -p listen
cargo install cargo-about --locked    # once
packaging/build-rpm.sh

packaging/build-rpm.sh produces two files in dist/:

  • listen-<version>-x86_64.tar.gz, a portable tarball with the binary, the desktop file, the icon, LICENSE, NOTICE.md, README.md and THIRD_PARTY_LICENSES.html.
  • listen-<version>-1.<dist>.x86_64.rpm, built by rpmbuild from packaging/listen.spec, which installs the binary, the desktop entry (io.github.leks2205.Listen.desktop) and the icon, and declares the run-time dependencies (mpv, PipeWire tools, the display libraries, whipper, flac and cdrdao; yt-dlp and Node.js as recommended packages). On a machine that is not Fedora the script defines a dist tag so rpmbuild still works.

The RPM is a binary package of the prebuilt executable; it does not compile anything.

Windows installer

packaging/windows/build-installer.sh [--no-build] [--out DIR] builds dist/Listen-Setup-<version>.exe on Linux:

  1. Cross-builds listen.exe for x86_64-pc-windows-gnu (skipped with --no-build). See Building from source.
  2. Assembles a folder with listen.exe, LICENSE, NOTICE.md and a fresh THIRD_PARTY_LICENSES.html. mpv, yt-dlp and Deno are not bundled; the installed app obtains them with winget on first start.
  3. Downloads Inno Setup into a cache ($LISTEN_WIN_CACHE, default ~/.cache/listen-windows), checking a pinned SHA-256 before using it, installs it into a Wine prefix ($LISTEN_WINE_PREFIX) and compiles packaging/windows/listen.iss with it.

Needs wine, curl, sha256sum, cargo-about and the MinGW toolchain. The installer is per-user: it installs to %LOCALAPPDATA%\Programs\Listen and does not ask for administrator rights. The script prints the installer’s SHA-256 at the end. packaging/windows/test-installer-wine.sh is a helper for trying the installer under Wine.

Note: A fresh Wine prefix can hang on some Fedora releases. The script header explains the workaround it uses (it copies an existing ~/.wine prefix and fills in the 32-bit system files).

Third-party licenses

THIRD_PARTY_LICENSES.html lists the license of every Rust crate in the build. It is generated by cargo about generate packaging/about.hbs, using the rules in about.toml:

  • accepted lists the allowed SPDX licenses (MIT, Apache-2.0, BSD, ISC, Zlib, MPL-2.0, Unicode, GPL-3.0 for the GPL parts and so on). A dependency under any other license makes the generation fail, which is the point: review it before shipping.
  • targets covers both x86_64-unknown-linux-gnu and x86_64-pc-windows-gnu, so one file serves both platforms.
  • Build and dev dependencies are ignored, and a workaround is set for the ring crate.

packaging/about.hbs is the page template. Fonts, icons and the parts derived from Feishin are listed in NOTICE.md, which ships next to the page.

GitHub releases and the updater

A release on GitHub carries the RPM, the tarball, the Windows installer and a text file named SHA256SUMS. Create the checksums from inside dist/:

cd dist
sha256sum listen-*.rpm listen-*.tar.gz Listen-Setup-*.exe > SHA256SUMS

The in-app updater (app/src/app/updater.rs) reads the repository’s releases through the GitHub API, picks the asset that fits how Listen was installed (the RPM on Fedora, the installer on Windows, or the tarball, whose binary replaces the one in ~/.local/bin), downloads it and refuses to install it unless its SHA-256 matches the line in SHA256SUMS. A release without SHA256SUMS cannot be installed by the updater. Pre-releases are only offered to users who chose the beta update channel. See Updates for the user side.

YouTube Music internals

This page describes how the YouTube Music source (crates/listen-ytmusic) works. For the user side, see YouTube Music.

Note: Listen’s YouTube Music support is unofficial and not affiliated with Google or YouTube. It uses undocumented interfaces that can change without notice and may break at any time. Users sign in with their own account at their own risk. Listen does not download YouTube Music songs for offline use; songs are streamed only. yt-dlp is a separate program that the user installs.

Building blocks

PartImplementation
Library, search, albums, artists, playlists, likes, history, lyricsThe ytmapi-rs crate (version 0.3.3, features rustls and simplified-queries), which speaks YouTube Music’s InnerTube interface in the same way as the ytmusicapi project. Entry point: crates/listen-ytmusic/src/lib.rs.
Audio streamsyt-dlp resolves a song to a direct stream URL that is handed to mpv (ytdlp.rs). URLs are cached until about 15 minutes before their expire= time.
JavaScript runtimeyt-dlp needs Deno or Node.js to work with YouTube. Listen looks for deno and node on PATH and in the usual per-user locations (for example ~/.nvm and ~/.local/bin), because desktop launchers often do not pass the shell’s PATH.
Radio and Auto-DJThe “watch next” list (get_watch_playlist_from_video_id).
HistoryPlaying a track reports it with add_history_item, so recommendations stay current.

Helper program paths can be overridden with LISTEN_YTDLP for development, and are set in Settings -> Advanced -> Helper programs for users.

Sign-in

Google’s own sign-in flow for third-party apps (OAuth) is not usable with YouTube Music, so Listen works with the session of the user’s browser or with an exported cookie file.

Reading a browser’s session

browser.rs finds browsers on the computer that are signed in to YouTube and reads their youtube.com cookies. Only the location (browser profile and channel) is stored in the keyring, never the cookies; they are read again on every start.

Browser familyHow the cookies are read
Chromium-based: Chrome, Chromium, Brave, Edge, Vivaldi, Ecosia (also as Flatpaks)The Cookies SQLite database is copied first, because the browser locks the original while it runs. Values marked v10 use Chromium’s built-in key. Values marked v11 need the browser’s password from the Secret Service (read with secret-tool). Databases from Chromium 130 on (meta version 24 or higher) prefix each value with a SHA-256 of the host, which Listen strips.
Firefoxcookies.sqlite, which is not encrypted.

As a fallback, Listen accepts an exported cookies file (JSON or cookies.txt format, Cookie-Editor style JSON, or a raw Cookie header). It keeps only the cookies a browser would send to music.youtube.com and requires SAPISID. Without any cookies Listen runs in guest mode with a consent-only cookie (SOCS): search, albums, artists, radio and playback work; there is no personal library.

Channels and brand accounts

A Google account can have several YouTube identities: its own and brand-account channels. The music library belongs to one of them. After sign-in, channels.rs lists the identities with their library size (using account/accounts_list) and the user picks one. Requests then carry the X-Goog-PageId header for that channel (token.rs). Without it, a library on a brand channel looks empty.

Library mapping and ytmapi-rs notes

  • IDs are newtypes; convert with YoutubeID::from_raw and get_raw.
  • Playlist browse ids need the VL prefix for reading (get_playlist_tracks); editing uses the raw id.
  • “Liked Music” is the playlist VLLM. It is hidden from the library playlist list, so Listen adds it back.
  • Simplified queries return only the first page. yt.stream(&Query) collects all pages.
  • The ytmapi-rs playlist and library-song parsers fail the whole list when one entry lacks a field. Listen reads song lists itself (home::song_page): tolerant of missing fields, all continuation pages, both continuation styles.
  • Tracks are library songs plus Liked Music. Albums are saved albums plus the albums of those songs. Artists are the artists of library songs plus subscribed artists.
  • Durations and years arrive as strings. Search results carry one artist string without ids. Album tracks have no artists or thumbnails of their own (the album’s are used). Artist top songs have no duration.
  • There is no home-feed query in the crate. Listen requests browse FEmusic_home itself and parses the shelves (home.rs): quick picks, mixes and playlists, albums, plus two continuation pages.
  • Uploaded music appears as an “Uploads” list in Playlists, only when the account has uploads.
  • The song/video switch (player bar, YouTube Music songs only, off by default) starts a second muted mpv window with the music video, kept within 0.7 s of the audio. The counterpart video id comes from the next endpoint, else the song’s own video.

Request budget

YouTube limits how fast one client may resolve streams; going over leads to “confirm you’re not a bot” answers. budget.rs keeps Listen’s background work well below that:

ConstantValueMeaning
BACKGROUND_MIN_GAP10 sMinimum distance between background requests. Any request, urgent or not, pushes the next background slot back.
BACKGROUND_PER_HOUR150Background requests only start while fewer than this many requests of any kind happened in the last hour.
BACKGROUND_MAX_WAIT15 sHow long a background request waits for a slot before giving up. The caller tries later.

Requests are either urgent (Urgency::Now: playback, the current and next queue song, retries) or background (analysis of the AI DJ’s candidate pool). Urgent requests always pass but are counted. Background work gets the slots that are left. YouTube Music songs are therefore analysed only on demand, never in a full-library crawl.

When it breaks

YouTube changes its interfaces often. When playback fails, update yt-dlp first. When library pages fail, a newer ytmapi-rs is usually needed. Two helpers:

  • listen --check-youtube-music signs in through the browser session and prints channels, counts and whether every playlist and album opens. It prints counts only, never cookies.
  • LISTEN_YTM_LIVE=1 cargo test -p listen-ytmusic --test live_ytdlp runs an opt-in live check. See Tests.

DJ transitions internals

This page is a short overview of how Listen mixes one song into the next. The measurements, benchmark tables, prototype results and the end-to-end test report are in the full design notes: docs/dj-transitions.md on GitHub. For the user side, see DJ transitions and Song analysis.

The pipeline

 song --> analysis --> store --> planner --> two mpv decks
          (helper)     (shared)  (listen-mix)  (phase lock, EQ, speed, volume)

1. Analysis

crates/listen-analysis decodes each song through mpv to 22,050 Hz audio, so the beat grid is in the same time base as playback (mpv removes MP3 encoder delay exactly). From the samples it computes:

  • Beats and downbeats with the neural beat tracker beat-this (small model, MIT-licensed, run with the pure-Rust rten). The model files are downloaded once on first use and checked against a pinned SHA-256. An own dynamic-programming tracker is the fallback when the model is not available; a BPM tag can correct its half-tempo errors.
  • Key, with an own detector based on Temperley profiles over spectral-peak chroma, reported as Camelot keys with a confidence.
  • Structure: intro and outro length in bars, vocal and breakdown sections, an energy curve.
  • Timbre with the bliss-audio vector, loudness (EBU R128) and a waveform.

Analysis runs in a short-lived helper process (listen --analysis-worker) and results go to a shard-based store that can be shared between computers. YouTube Music songs are analysed on demand only, within a request budget; see YouTube Music internals.

2. Planning

crates/listen-mix contains no DSP and no mpv code, which makes it cheap to test.

  • score rates how well one song flows into another (tempo, key, energy, timbre, mixability, repetition) and orders DJ picks with a beam search.
  • plan decides which pairs may be mixed at all (mix_eligible) and builds a TransitionPlan: the kind of transition (a beat-matched blend or a plain fade), where the outgoing song stops and the incoming one starts, envelopes for volume, bass and filters, and speed ramps. Songs more than a few percent apart in tempo get an echo-out or a cut (no overlap of the dry signals, each deck at its own tempo; best_handover) instead of a beat match, and an echo-out or cut also beats a filter-out over clashing vocals; a fade is left for songs without a beat grid and for AI DJ talk-overs. Each blend candidate fits its tempo to the overlapping bars (local_match): the octave from the overlap’s length, then a least-squares speed ratio over every beat of the overlap, anchored at the shared first downbeat, and a linear glide (TransitionPlan::in_glide, read through in_speed_at by the desktop mixer, the preview renderer and the Android mixer) when that takes more than 2 ms of drift off and changes the speed by at most 4 %. When a grid slows down and picks up again inside the blend (a ritardando, a live drummer), a speed curve with one knot per outgoing bar (fit_curve: the speed linear between knots, its integral fitted to the incoming beats by least squares, second differences penalised more until the curve stays within 4 %) replaces the ramp if it takes another 2 ms off, or if the ramp leaves more than 4 ms and the curve gets any closer (curve_wins); it is TransitionPlan::in_curve (wall seconds after the mix point, speed), in_glide keeps its ends for older readers, and in_speed_at interpolates it. Beats past the last one the analyser found (the grid extrapolates at the nominal tempo) are left out of the fits. On the bug-129 pairs: DAUM → Being Freezed (8-bar BeatBlend) 25.6 → 1.3 ms, Falling Leaves are Beautiful → Mutuals (4-bar ShortBlend) 8.5 → 2.8 ms (4.1 ms with its 3.9 % ramp alone; measured on every grid beat between the mix point and the stop, in wall time). The drift that is left costs DRIFT_PER_S beyond 4 ms. On 427 real history pairs the plans played without phase nudges keep 193 of 210 beat-mixed pairs within 4 ms on every beat (98 of 222 with the songs’ average tempos; worst 53 ms instead of 1.3 s); 12 pairs whose overlapping bars can’t be matched become echo-outs or cuts. PlanCtx::no_echo (set by the app when the outgoing song itself came in through an echo-out, MixState::entered_echo) drops the echo candidates, so two echo-outs never follow each other; bridge::gap counts an echo-out or cut as “no beat-matched join”, bridge::always_try exempts such pairs from the bridge chance and bridge::choose then asks no flow gain of the legs over the direct pair (only that they flow no worse). The echo is four adelay taps behind a send volume mixed back by amix in the deck’s lavfi chain (live delays/weights/volume commands, listen_core::settings::DECK_ECHO_*). amix and volume step in one sample, so the send and the dry signal are switched by afade gates whose start_time is set to the planned file time 1.5 s ahead (deck_echo_commands): each switch is a 5 ms ramp at exactly that sample, as in listen_mix::echo, the same effect on samples for the preview and the Android mixer.
  • loudness (contract C5) also holds the blend gain: plan stores BlendLevels in each overlapping plan (both decks’ local loudness every 0.5 s across the blend after the decks’ filters, plus the 4 s edge levels before and after), and blend_trim(plan, t, g_out, g_in, deck_gain_out_db, deck_gain_in_db) is the trim both engines and render apply to both decks: the summed loudness follows the line between the edge levels, weighted by how much the decks overlap, clamped to −6..+3 dB. It replaced the fixed 0.85 trim. LocalLevel is Features::lufs anchored on the per-bar curves and power-averaged over 3 s: the energy curve is plain power, so each bar is corrected towards K-weighting from its bass share (the low-band curve against the energy curve, scaled by BASS_SHARE_SCALE of the bound the curves allow) and its brightness (centroid curve, up to BRIGHT_DB); against the audio’s 3 s short-term loudness that is 0.75 dB sd on 78 bench songs (1.04 before) and 0.72 on 47 others (0.96). The same bass share gives what the bass swap’s shelf takes (LocalLevel::bass_loss_lu, 1.0 LU sd against the song played through the shelf; the fixed 2 LU it replaced missed by more than 3 LU in 18 % of windows), and plan_levels takes every filter’s loss off the deck’s level, so the trim makes up for a bass swap instead of cutting both decks as if the outgoing were still whole (bug 148). --check-mix --levels prints the model, the measured level and the level through the −24 dB shelf (measured_no_bass). A boost may take a deck above unity: the desktop sends mpv volumes up to its default volume-max of 130 % for it (listen_player::MAX_VOLUME), so the app plays what render and verify model. Handovers get none.
  • render makes an offline preview of a plan, available through listen --check-mix --render.
  • verify is render-and-verify: plan_verified takes the planner’s options in order (plan::alternatives: the chosen plan, then the other candidates and handovers by score, then the plain fade) and plays each one through on the analysis curves every 0.1 s. It uses both decks’ local loudness (loudness::LocalLevel), the vocal curve with lyrics merged in, the gain envelope, the equal-loudness trim, the loudness the EQ moves take (the bass shelf from the song’s own bass share) and their rough vocal losses, and the echo repeats. It arms the first plan that passes the gates: a hole or bump over 1.5 LU (against both the songs’ own levelled loudness and the edge line; a modelled hole counts 0.6 LU deeper, HOLE_MARGIN_LU, the curves’ error against rendered blends), more than 1 s of audible vocals on both decks, or a mid-line exit (lyric cues only). The desktop plans before it fetches the incoming file, so the check runs on curves rather than audio. audio_levels and audio_dip_bump measure a rendered preview the same way (BS.1770 K-weighting over left and right, 3 s short-term) for --check-mix --render. The reference for each deck is that deck alone on the preview’s own timeline (render::render_decks): a tempo ramp before the blend moves the outgoing up to a second away from its file, and measuring against the file turned level steps at the mix point into holes the mix doesn’t have. With the filter losses in the trim the planner’s first choice passes on all 427 real history pairs (it failed in 18 before, mostly a hole within the margin), and the check takes 0.08 ms on average. On the 104-pair render bench (96 blends) the largest rendered hole went from 2.98 to 0.30 LU (5 over 1.5 before), the largest bump stayed 1.11.
  • lyric merges a VocalMap (from listen_lyrics::vocal_map: sung stretches, line ends, chorus occurrences of synced lyrics) into bars.vocal and sets bars.cue flags (LINE_END, ENTRY, CHORUS, CHORUS_END). It drops lyrics that are anti-correlated with the audio vocal curve or fit clearly better shifted by up to 6 bars. The planner then adds cue-outs after a sung phrase or at a breakdown in the last 40 % (cut cost 0.02/s), cue-ins 1, 2 or 4 bars before a verse or chorus entry (skip cost 0.01/s), +0.5/+0.3 when a blend ends on the incoming chorus/entry, and −0.5 for stopping the outgoing mid-line. Without lyrics the plans are unchanged. The desktop looks lyrics up for the playing and next song (app/src/app/mix/vocal.rs) and re-plans when they arrive before the preload.

3. Two mpv decks

app/src/app/mix/ and decks.rs run a plan on two mpv players:

  1. About 20 seconds before the mix point the incoming song is loaded paused on the idle deck, with its start position set.
  2. It is unpaused at the planned moment. A learned latency compensates for the start-up delay.
  3. Phase lock: during the silent pre-roll bar both decks’ audio-pts are read back to back, and the incoming deck’s speed is nudged by about 0.5 percent (up to 2 percent while it is still silent) until the beats line up. The loop keeps running through the blend to catch underruns. Seeks are not used to correct the phase.
  4. Volume, bass, high-pass and low-pass changes are sent slightly early (about 240 ms with the 0.1 s audio buffer) and as ramps of at least one beat, so the jitter of mpv’s filter commands is inaudible. Tempo matching uses the rubberband filter, with scaletempo2 as a fallback.
  5. Halfway through the blend the incoming deck becomes the active deck.

Anything unexpected (a late deck, a skip, a seek, a pause) cancels the blend and falls back to mpv’s gapless playback.

Measured accuracy

In the prototype, the two decks stayed aligned with a median error below 0.1 ms and a 95th percentile below 1 ms once the lock converged. The design target was a median of 10 ms or less. The end-to-end test (tools/dj-e2e.sh, described in Tests) checks real blends for gaps, level and doubled beats.

Tempo matching (heart-rate mode)

The heart-rate mode of both apps uses listen_mix::tempo: a reading (heart beats or steps per minute from a Wear OS watch, a Bluetooth strap or the phone’s step detector; on the desktop a Bluetooth sensor) is smoothed with a 30-second time constant and turned into a tempo target clamped to 70–180 BPM, ± 8 BPM, with half and double time counting (85 BPM fits 170). When the target has moved more than 5 BPM since the last time, the upcoming automatic queue items are re-ranked: songs within 4 BPM stay, closest first, the others make room for tempo-targeted Auto-DJ picks. Songs added by hand and the playing song are never touched. Music does not measurably change heart rate during exercise; the mode picks music that fits the effort, it is not training guidance.

The fit is judged at the faster pulse (tempo::fit_distance = min(|b − t|, |b − 2t|, |2b − t|)), so a 70 BPM target fits 62–78, 132–148 and 31–39 BPM and a 130 BPM song does not fit 70. TempoTarget::distance halves a double-time song instead (130 counts as 65) and is not used for the fit. Fills go through tempo::tempo_fill: the fitting fetched songs, topped up from the analysis store (closest to the current song’s energy and timbre, never excluded, queued or played songs), and the nearest misfits only when the store is short too (TempoFill::padded_note says so). The AI DJ’s prompt gets listen_dj::tempo::rule and a listen_dj::tempo::fit_note per candidate, the same on both apps.

Where to read more

The full notes explain why each choice was made, with results for the analyser benchmark, key detection, the mpv deck prototype and the end-to-end run: github.com/leks2205/Listen/blob/main/docs/dj-transitions.md.

Bridge scenes

listen_core::scene keeps bridges in the pair’s scene. A Scene is a language (ISO 639-1, or instrumental) plus genre Families bits (pop, hip hop, r&b, rock, electronic, jazz, folk, trot, latin, classical, ambient, blues, country, reggae), read from the describe-it tags_en (Scene::from_tags), the song’s genres (from_genres), the artist’s other tagged songs (SceneIndex, language held by ≥ 60 % of them, families by ≥ 1/3) and the title script (Hangul, kana; language only), strongest first. compare fails on a different language or disjoint families (pop~r&b, hip hop~r&b, pop~electronic, rock~folk, jazz~latin, r&b~blues, jazz~blues count half). Without comparable tags the CLaMP 3 audio cosine decides: ≥ AUDIO_SAME (0.60) is one scene. On the index of 2026-11-06 (305 songs) K-pop↔K-pop pairs have audio cosines p5/p25/p50/p95 0.39/0.49/0.59/0.82 and K-pop↔US hip hop 0.28/0.35/0.41/0.56 (48 % vs 2 % at ≥ 0.60); the tag-embedding cosines separate completely (K-pop pairs p5 0.49, K-pop↔US hip hop p95 0.44). The same artist is always one scene; artists heard within 20 minutes of each other (Neighbours::from_history) fill an unknown. Gate::judge: a pair in one scene needs a bridge in it, two scenes need a bridge from one of them, an unknown candidate is rejected when the pair is known, and no gate applies when neither song is known. listen_analysis::bridge_scene_gate filters the candidates and gives each a score (0..1) that bridge::choose_scored takes off the cost (×0.3). The desktop loads the index from Listen/embeddings/v1/clamp3 next to the analysis store (analysis::keep_scenes, reloaded when the files change); the phone mirrors listen-server’s GET /v1/scenes?since= (SceneRecord: tags and the audio embedding as bytes). listen --check-bridges <analysis copy> <embeddings dir> <history.jsonl> prints the bridge chosen without and with the gate for history pairs.

Eras. Scene::era is a decade start (1970 = before 1980): an explicit decade or year in the tags (“2020s”, “90s ballad”, “1999”), else a K-pop generation (1st → 1990s, 2nd → 2000s, 3rd → 2010s, 4th/5th → 2020s), else the song’s year (SceneIndex::profile_dated, listen_analysis::scene_profile passes Song::year), else the artist’s (common_era: the median when ≥ 60 % are within a decade of it), else the up to 5 closest-sounding dated songs (cosine ≥ AUDIO_SAME, at least 3, agreeing as above). compare: both known and more than ERA_SPAN (10) apart is Other("era"); a decade apart scores ×0.9; one side unknown needs language and genre both matched (×0.85), else Unknown. History neighbours never fill across a known/unknown era. Reject::OtherEra and Tally::other_era count those.

Heart-rate tempo picks. scene::Session (built by listen_analysis::tempo_session from the current song, the songs before it and the queued ones; the first SESSION_LEN = 5 known) finds the member most others share a scene with; with a majority its merged profile (most common language and era, families at least half have) is the session scene, otherwise every member’s scene counts (mixed). judge: the session’s artists pass, a candidate must compare as one scene with the majority (or fit any member when mixed), an unknown one is rejected, no gate when nothing is known. listen_analysis::tempo_scene_filter wraps it with the heard set (played history songs, favourites) as a SceneFilter for listen_mix::tempo::tempo_fill, which gates only the store top-up (the DJ’s pool and its padding stay), puts heard songs first and takes 0.3 × the scene score off the sound cost. TempoFill::scene_note is the log line. listen --check-tempo <analysis copy> <embeddings dir> <history.jsonl> --bpm 146 --probe "Artist – Title" replays a top-up without and with the gate.