Skip to content

Conversation

daredoes
Copy link

@daredoes daredoes commented Jun 10, 2025

WORKING JUKEBOX MODE!

still needs a high quality controller though

The jukebox mode as it is implemented has many issues, part of which came from using an MPV process per track, instead of an MPV process for all tracks. MPV is super powerful, but the documentation is not ripe with examples of what to do. Through trial and error (and some Google Gemini to help with the unknown MPV stuff) I have come about with the minimum viable solution for Navidrome to have a working jukebox mode (and learned a lot about MPV).

Creating a file with mkfifo /tmp/navidrome and running navidrome (this branch) and snapcast on the same system seems to work. Running snapcast via docker and navidrome locally does not work on my mac. Might have something to do with file binding, or how the pipe works, idk.

The file between the two must be made with mkfifo as far as I can tell, otherwise mpv writes the content too fast

Template command

MPVCmdTemplate = "mpv --no-audio-display --gapless-audio=yes --no-video --vid=no --ytdl=no --idle --input-ipc-server=%s --audio-channels=stereo --audio-samplerate=48000 --audio-format=s16 --ao=pcm --ao-pcm-file=/tmp/navififo"

The magic of how this feature works

MPV has a lot of great features built-in, but not everything. To supplement that, it supports running plugin scripts. Through usage of a custom plugin script we can attach IDs to each track we load in to play, allowing us to later retrieve the current playlist from MPV and fetch the data from our database for the get action. This provides apps with all the information needed for cover art.

Optimizations

  • The Lua script could be updated to push more events to the Go server, such as the items in the playlist or the active song so they do not need to be polled upon request from a client.
  • Requiring the user to include the --idle options in the configuration could be converted into more user-friendly switches like MPVNoAudioDisplay

Features Supported

  • get
  • status
  • set
  • add
  • clear
  • remove
  • setGain
  • shuffle
  • start
  • stop
  • skip
    The following features would be nice to implement as they are supported by MPV. They would be an extension of the subsonic api
  • loop playlist/file
  • set position
  • play radio stream

Closes #3256

Changes

  • Moves the control of the MPV command from track creation to server start-up/shut-down.
  • Updates the commands for the Track model to control the existing IPC socket instead of creating a new one,
  • Updates the default MPV Command Template to stay idle and ensure no attempts at video output occur
  • Adds a custom lua script that provides information back to Navidrome about the items in the playlist
  • Removes the need to pass the filename into the MPV Command, as it is now passed via IPC

Screenshots or Videos

Related Issues and Pull Requests(if any)
#3852
#3637
#3022
#2771

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary of Changes

Hello @daredoes, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly refactors the jukebox playback mode by moving from a per-track MPV process model to a single, persistent MPV instance controlled via IPC. This change aims to address existing issues and provide a more robust foundation for jukebox functionality. A new Lua script is introduced to bridge the gap between MPV's playlist management and Navidrome's media file IDs.

Highlights

  • Single MPV Instance: The jukebox mode is refactored to use a single, long-running MPV process instead of launching a new process for each track. This is expected to improve stability and performance.
  • IPC Communication: Control of the MPV process is now handled via its IPC socket, allowing Navidrome to send commands (play, pause, skip, etc.) and query status.
  • Lua Script for Playlist Management: A custom Lua script is added to MPV. This script maintains a cache mapping file paths to Navidrome media file IDs and exposes the ordered list of IDs in the current MPV playlist via an MPV property, which Navidrome can then query.
  • Refactored Playback Logic: The playbackDevice and PlaybackServer components are updated to delegate playback control actions (Add, Clear, Remove, Start, Stop, Skip, SetGain, Shuffle, Get, Status) to the single MPV connection managed by the PlaybackServer.
  • Updated MPV Command Template: The default MPV command template is modified to remove the per-file argument (%f) and include the new Lua script using the --script option.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configureGemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request significantly refactors the jukebox mode to use a single, persistent MPV process managed via an IPC socket and a Lua script, instead of launching an MPV process per track. This is a substantial improvement for stability and resource management.

The changes involve:

  • Introducing an MpvConnection in core/playback/mpv/mpv.go to manage the single MPV instance and its IPC communication.
  • Adding a Lua script (jukebox.lua) that runs within MPV to provide playlist information (track IDs) back to Navidrome.
  • Modifying core/playback/playbackserver.go to be the central point for MPV control, holding the MpvConnection and exposing methods for various playback actions.
  • Updating core/playback/device.go to delegate most Jukebox commands to the PlaybackServer.
  • Adjusting Subsonic API helpers and Jukebox control logic to work with track IDs instead of full MediaFile objects directly from the playlist.

Overall, the refactoring appears well-executed and addresses the core issue of multiple MPV processes. The use of a Lua script for playlist data retrieval is a clever solution.

I've identified a few areas for improvement related to correctness and robustness.

@daredoes
Copy link
Author

@tcurdt Could I get your input on this PR?

@tcurdt
Copy link
Contributor

tcurdt commented Jun 11, 2025

I am not sure I am the one to give input but since you asked for it...

I like how you separated out the player state.
IIUC the lua script helps to keep the playlist in sync.
I am not sure that's really required - but it's a smart approach.
And IIUC this also gets around the previous argument quoting/parsing problem?

How would adding setPosition support work?

Overall it's looks like great improvements. Very cool.

@daredoes
Copy link
Author

@tcurdt I appreciate the review! You're the most active contributor besides myself that I can think of who is specifically trying to use this for snapcast playback.

The lua script is required since MPV now manages the playlist while we still need to return data about the playlist in the get action of the subsonic API (this provides data like the cover art, playback length, artist ID to link to, album ID to link to, etc). This extends to no longer needing to pass the file name to the MPV command, as it is passed via IPC socket with the loadfile command which loads it into the MPV playlist.

setPosition isn't defined by the subsonic api. The subsonic api is really barebones, and seems to really upon the player to implement features like seek, set position, next track, and previous track. Yet somehow, this barebones API has all it needs. It encompasses all of the previously described features in the skip action, which takes an index for the song in the playlist, and an offset for where in the song to skip to.

  • Previous song: Skip (currentIndex-1, 0)
  • Next song: Skip (currentIndex+1, 0)
  • setPosition: Skip (currentIndex, desiredPosition)

An action that I'd like to support in the API, but isn't outlined anywhere, is the ability to loop a playlist, or loop the playing song. It's supported by MPV very easily, but it is not documented in the subsonic API. This would make it an extension on the current standard. To be fair, the current standard doesn't seem to be widely adopted or actively improved.

@daredoes
Copy link
Author

daredoes commented Jul 7, 2025

@deluan I'd love to get this looked at and merged in at some point if you have the time

@daredoes
Copy link
Author

daredoes commented Aug 4, 2025

Bump :(

waiting to start on creating UI/UX for this feature until its merged in for testing against

@daredoes
Copy link
Author

Bumping again I guess :(

librespot broke recently and this would have been awesome to fall back to.

@daredoes
Copy link
Author

@deluan Hope the ping isn't a bother. Trying not to let this PR get lost to time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Bug]: mpv errors when trying to use jukebox mode
2 participants